OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stdint.h> | 5 #include <stdint.h> |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <utility> | 8 #include <utility> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
13 #include "base/macros.h" | 13 #include "base/macros.h" |
14 #include "base/scoped_observer.h" | 14 #include "base/scoped_observer.h" |
15 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
16 #include "chrome/browser/browser_process.h" | 16 #include "chrome/browser/browser_process.h" |
17 #include "chrome/browser/chromeos/printer_detector/printer_detector.h" | 17 #include "chrome/browser/chromeos/printer_detector/printer_detector.h" |
18 #include "chrome/browser/chromeos/printing/ppd_provider_factory.h" | |
19 #include "chrome/browser/chromeos/printing/printer_configurer.h" | |
20 #include "chrome/browser/chromeos/printing/printers_manager_factory.h" | |
21 #include "chrome/browser/chromeos/printing/usb_util.h" | |
18 #include "chrome/browser/chromeos/profiles/profile_helper.h" | 22 #include "chrome/browser/chromeos/profiles/profile_helper.h" |
19 #include "chrome/browser/notifications/notification.h" | 23 #include "chromeos/dbus/dbus_thread_manager.h" |
20 #include "chrome/browser/notifications/notification_delegate.h" | 24 #include "chromeos/dbus/debug_daemon_client.h" |
21 #include "chrome/browser/notifications/notification_ui_manager.h" | 25 #include "chromeos/printing/ppd_provider.h" |
22 #include "chrome/browser/ui/browser_navigator.h" | |
23 #include "chrome/browser/ui/browser_navigator_params.h" | |
24 #include "chrome/common/url_constants.h" | |
25 #include "chrome/grit/generated_resources.h" | |
26 #include "chrome/grit/theme_resources.h" | |
27 #include "components/user_manager/user.h" | 26 #include "components/user_manager/user.h" |
28 #include "components/user_manager/user_manager.h" | 27 #include "components/user_manager/user_manager.h" |
28 #include "content/public/browser/browser_thread.h" | |
29 #include "device/base/device_client.h" | 29 #include "device/base/device_client.h" |
30 #include "device/usb/usb_device.h" | 30 #include "device/usb/usb_device.h" |
31 #include "device/usb/usb_device_filter.h" | 31 #include "device/usb/usb_device_filter.h" |
32 #include "device/usb/usb_service.h" | 32 #include "device/usb/usb_service.h" |
33 #include "extensions/browser/extension_registry.h" | 33 #include "extensions/browser/extension_registry.h" |
34 #include "extensions/browser/extension_system.h" | 34 #include "extensions/browser/extension_system.h" |
35 #include "extensions/common/one_shot_event.h" | 35 #include "extensions/common/one_shot_event.h" |
36 #include "ui/base/l10n/l10n_util.h" | |
37 #include "ui/base/resource/resource_bundle.h" | |
38 | 36 |
39 namespace chromeos { | 37 namespace chromeos { |
40 namespace { | 38 namespace { |
41 | 39 |
42 const char kUSBPrinterFoundNotificationID[] = | 40 using printing::PpdProvider; |
43 "chrome://settings/cupsPrinters/printer_found"; | |
44 | 41 |
45 // Base class used for printer USB interfaces | 42 // We have to carry quite a bit of data through to the callbacks for |
46 // (https://www.usb.org/developers/defined_class). | 43 // getting a printer set up. Rather than have a bunch of parameters |
47 const uint8_t kPrinterInterfaceClass = 7; | 44 // in a bunch of functions below, this struct aggregates everything |
45 // we need to keep around during the setup. | |
46 struct SetUpPrinterData { | |
47 // The configurer running the SetUpPrinter call. | |
48 std::unique_ptr<PrinterConfigurer> configurer; | |
48 | 49 |
49 // USBPrinterSetupNotificationDelegate takes a pointer to the Impl class, so | 50 // The printer being set up. |
50 // we have to forward declare it. | 51 std::unique_ptr<Printer> printer; |
51 class CupsPrinterDetectorImpl; | |
52 | 52 |
53 class USBPrinterSetupNotificationDelegate : public NotificationDelegate { | 53 // The usb device causing this setup flow. |
54 public: | 54 scoped_refptr<device::UsbDevice> device; |
55 explicit USBPrinterSetupNotificationDelegate( | |
56 CupsPrinterDetectorImpl* printer_detector) | |
57 : printer_detector_(printer_detector) {} | |
58 | 55 |
59 // NotificationDelegate override: | 56 // True if this printer is one that the user doesn't already have a |
60 std::string id() const override { return kUSBPrinterFoundNotificationID; } | 57 // configuration for. |
58 bool is_new; | |
61 | 59 |
62 // This is defined out of line because it needs the PrinterDetectorImpl | 60 // True if this was a printer that was plugged in during the session, false if |
63 // full class declaration, not just the forward declaration. | 61 // it was already plugged in when the session started. |
64 void ButtonClick(int button_index) override; | 62 bool hotplugged; |
65 | |
66 bool HasClickedListener() override { return true; } | |
67 | |
68 private: | |
69 ~USBPrinterSetupNotificationDelegate() override = default; | |
70 | |
71 CupsPrinterDetectorImpl* printer_detector_; | |
72 | |
73 DISALLOW_COPY_AND_ASSIGN(USBPrinterSetupNotificationDelegate); | |
74 }; | 63 }; |
75 | 64 |
76 // The PrinterDetector that drives the flow for setting up a USB printer to use | 65 // The PrinterDetector that drives the flow for setting up a USB printer to use |
77 // CUPS backend. | 66 // CUPS backend. |
78 class CupsPrinterDetectorImpl : public PrinterDetector, | 67 class CupsPrinterDetectorImpl : public PrinterDetector, |
79 public device::UsbService::Observer { | 68 public device::UsbService::Observer { |
80 public: | 69 public: |
81 explicit CupsPrinterDetectorImpl(Profile* profile) | 70 explicit CupsPrinterDetectorImpl(Profile* profile) |
82 : profile_(profile), observer_(this), weak_ptr_factory_(this) { | 71 : profile_(profile), observer_(this), weak_ptr_factory_(this) { |
83 extensions::ExtensionSystem::Get(profile)->ready().Post( | 72 extensions::ExtensionSystem::Get(profile)->ready().Post( |
84 FROM_HERE, base::Bind(&CupsPrinterDetectorImpl::Initialize, | 73 FROM_HERE, base::Bind(&CupsPrinterDetectorImpl::Initialize, |
85 weak_ptr_factory_.GetWeakPtr())); | 74 weak_ptr_factory_.GetWeakPtr())); |
86 } | 75 } |
87 ~CupsPrinterDetectorImpl() override = default; | 76 ~CupsPrinterDetectorImpl() override = default; |
88 | 77 |
89 void ClickOnNotificationButton(int button_index) { | |
90 // Remove the old notification first. | |
91 const ProfileID profile_id = NotificationUIManager::GetProfileID(profile_); | |
92 g_browser_process->notification_ui_manager()->CancelById( | |
93 kUSBPrinterFoundNotificationID, profile_id); | |
94 | |
95 if (command_ == ButtonCommand::SETUP) { | |
96 OnSetUpUSBPrinterStarted(); | |
97 // TODO(skau/xdai): call the CUPS backend to set up the USB printer and | |
98 // then call OnSetUpPrinterDone() or OnSetUpPrinterError() depending on | |
99 // the setup result. | |
100 } else if (command_ == ButtonCommand::CANCEL_SETUP) { | |
101 // TODO(skau/xdai): call the CUPS backend to cancel the printer setup. | |
102 } else if (command_ == ButtonCommand::GET_HELP) { | |
103 chrome::NavigateParams params(profile_, | |
104 GURL(chrome::kChromeUIMdCupsSettingsURL), | |
105 ui::PAGE_TRANSITION_LINK); | |
106 params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; | |
107 params.window_action = chrome::NavigateParams::SHOW_WINDOW; | |
108 chrome::Navigate(¶ms); | |
109 } | |
110 } | |
111 | |
112 private: | 78 private: |
113 // Action that should be performed when a notification button is clicked. | 79 // Called when the extension system is "ready", meaning everything has been |
114 enum class ButtonCommand { | 80 // created. |
115 SETUP, | 81 void Initialize() { |
116 CANCEL_SETUP, | |
117 CLOSE, | |
118 GET_HELP, | |
119 }; | |
120 | |
121 // UsbService::observer override: | |
122 void OnDeviceAdded(scoped_refptr<device::UsbDevice> device) override { | |
123 const user_manager::User* user = | 82 const user_manager::User* user = |
124 ProfileHelper::Get()->GetUserByProfile(profile_); | 83 ProfileHelper::Get()->GetUserByProfile(profile_); |
84 // Don't bother to listen for USB events unless we are the active user. | |
85 // | |
125 // TODO(justincarlson) - See if it's appropriate to relax any of these | 86 // TODO(justincarlson) - See if it's appropriate to relax any of these |
126 // constraints. | 87 // constraints. |
127 if (!user || !user->HasGaiaAccount() || !user_manager::UserManager::Get() || | 88 if (!user || !user->HasGaiaAccount() || !user_manager::UserManager::Get() || |
128 user != user_manager::UserManager::Get()->GetActiveUser()) { | 89 user != user_manager::UserManager::Get()->GetActiveUser()) { |
129 return; | 90 return; |
130 } | 91 } |
131 | |
132 device::UsbDeviceFilter printer_filter; | |
133 printer_filter.interface_class = kPrinterInterfaceClass; | |
134 if (!printer_filter.Matches(device)) | |
135 return; | |
136 | |
137 ShowUSBPrinterSetupNotification(device); | |
138 } | |
139 | |
140 // Initializes the printer detector. | |
141 void Initialize() { | |
142 device::UsbService* usb_service = | 92 device::UsbService* usb_service = |
143 device::DeviceClient::Get()->GetUsbService(); | 93 device::DeviceClient::Get()->GetUsbService(); |
144 if (!usb_service) | 94 if (!usb_service) { |
145 return; | 95 return; |
96 } | |
146 observer_.Add(usb_service); | 97 observer_.Add(usb_service); |
98 usb_service->GetDevices(base::Bind(&CupsPrinterDetectorImpl::OnGetDevices, | |
99 weak_ptr_factory_.GetWeakPtr())); | |
100 } | |
101 | |
102 // Callback for initial enumeration of usb devices. UsbService invokes | |
103 // this on the UI thread. | |
104 void OnGetDevices( | |
105 const std::vector<scoped_refptr<device::UsbDevice>>& devices) { | |
106 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
107 for (const auto& device : devices) { | |
108 if (!UsbDeviceIsPrinter(device)) { | |
109 continue; | |
110 } | |
111 if (!known_printers_.insert(device->guid()).second) { | |
skau
2017/03/11 00:00:34
Is this a common idiom? I didn't know that map::i
Carlson
2017/03/11 01:19:17
I would have guessed yes, but apparently not:
htt
| |
112 // Already dealt with this, don't need to do so again. | |
113 continue; | |
114 } | |
115 SetUpDevice(device, false); | |
116 } | |
117 } | |
118 | |
119 // UsbService::observer override. This runs on the UI thread. | |
120 void OnDeviceAdded(scoped_refptr<device::UsbDevice> device) override { | |
skau
2017/03/11 00:00:34
nit: DRY
Carlson
2017/03/11 01:19:16
Not sure which part you're referring to. You mean
skau
2017/03/13 21:56:25
Yes. I was referring to the code above. Sorry fo
Carlson
2017/03/15 00:31:15
Done.
| |
121 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
122 if (!UsbDeviceIsPrinter(device)) { | |
123 return; | |
124 } | |
125 if (!known_printers_.insert(device->guid()).second) { | |
126 // Already dealt with this, don't need to do so again. | |
127 return; | |
128 } | |
129 SetUpDevice(device, true); | |
130 } | |
131 | |
132 // UsbService::observer override. This runs on the UI thread. | |
133 void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) override { | |
134 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
135 if (!UsbDeviceIsPrinter(device)) { | |
136 return; | |
137 } | |
138 known_printers_.erase(device->guid()); | |
139 | |
140 // If this printer appears in the list of printers we've failed to set up, | |
141 // remove it. | |
142 failed_setup_printers_.erase(device->guid()); | |
143 } | |
144 | |
145 // This is called on the UI thread. | |
146 void SetUpDevice(scoped_refptr<device::UsbDevice> printer_device, | |
147 bool hotplugged) { | |
148 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
149 auto data = base::MakeUnique<SetUpPrinterData>(); | |
150 data->configurer = PrinterConfigurer::Create(profile_); | |
151 data->printer = base::MakeUnique<Printer>(); | |
152 data->device = printer_device; | |
153 data->is_new = true; | |
154 data->hotplugged = hotplugged; | |
155 if (!UsbDeviceToPrinter(*printer_device, data->printer.get())) { | |
156 LOG(ERROR) | |
157 << "Failed to convert usb device to printer, abandoning setup. " | |
158 << "Usb device details follow:"; | |
159 LOG(ERROR) << UsbPrinterDeviceDetailsAsString(*printer_device); | |
160 return; | |
161 } | |
162 auto existing_printers = | |
163 PrintersManagerFactory::GetForBrowserContext(profile_)->GetPrinters(); | |
skau
2017/03/11 00:00:34
TODO: add a GetPrinterByUri to PrintersManagerFact
Carlson
2017/03/11 01:19:16
Done.
| |
164 for (std::unique_ptr<Printer>& printer : existing_printers) { | |
165 if (printer->uri() == data->printer->uri()) { | |
166 // Found a match, so use the existing configuration. | |
167 *(data->printer) = *printer; | |
168 data->is_new = false; | |
169 | |
170 // Copy fields that will be invalidated by std::move. | |
171 auto* configurer_tmp = data->configurer.get(); | |
172 const Printer& printer_tmp = *(data->printer); | |
173 // off to the configurer. | |
174 configurer_tmp->SetUpPrinter( | |
175 printer_tmp, base::Bind(&CupsPrinterDetectorImpl::SetUpPrinterDone, | |
176 weak_ptr_factory_.GetWeakPtr(), | |
177 base::Passed(std::move(data)))); | |
178 return; | |
179 } | |
180 } | |
181 | |
182 // It's not a device we know about. First we see if we can get an exact | |
183 // driver match based on USB ids. | |
184 // | |
185 // TODO(justincarlson): Add a notification that we are attempting to set up | |
186 // this printer at this point. | |
187 auto ppd_provider = printing::CreateProvider(profile_); | |
skau
2017/03/11 00:00:34
scoped_refptf<PpdProvider>. In this case, it's im
Carlson
2017/03/11 01:19:16
Done.
| |
188 ppd_provider->ResolveUsbIds( | |
189 printer_device->vendor_id(), printer_device->product_id(), | |
190 base::Bind(&CupsPrinterDetectorImpl::ResolveUsbIdsDone, | |
191 weak_ptr_factory_.GetWeakPtr(), ppd_provider, | |
192 base::Passed(std::move(data)))); | |
193 } | |
194 | |
195 // Called when the query for a driver based on usb ids completes. | |
196 void ResolveUsbIdsDone(scoped_refptr<PpdProvider> provider, | |
197 std::unique_ptr<SetUpPrinterData> data, | |
198 PpdProvider::CallbackResultCode result, | |
199 const std::string& effective_make_and_model) { | |
200 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
201 if (result == PpdProvider::SUCCESS) { | |
202 // Got something based on usb ids. Go with it. | |
203 data->printer->mutable_ppd_reference()->effective_make_and_model = | |
204 effective_make_and_model; | |
205 } else { | |
206 // Couldn't figure this printer out based on usb ids, fall back to | |
207 // guessing the make/model string from what the USB system reports. | |
208 // | |
209 // TODO(justincarlson): Consider adding a mechanism for aggregating data | |
210 // about which usb devices are in the wild but unsupported? | |
211 // | |
212 // TODO(justincarlson): Possibly go deeper and query the IEEE1284 fields | |
213 // for make and model if we determine those are more likely to contain | |
214 // what we want. | |
215 data->printer->mutable_ppd_reference()->effective_make_and_model = | |
216 base::UTF16ToUTF8(data->device->manufacturer_string()) + " " + | |
217 base::UTF16ToUTF8(data->device->product_string()); | |
skau
2017/03/11 00:00:34
This function should have a name.
Carlson
2017/03/11 01:19:16
A function had no name. (Done.)
| |
218 } | |
219 | |
220 // Have to keep copies of some parameters that will be moved in the | |
221 // arguments and used in the same statement. | |
222 auto* configurer = data->configurer.get(); | |
223 auto* printer = data->printer.get(); | |
224 | |
225 configurer->SetUpPrinter( | |
226 *printer, base::Bind(&CupsPrinterDetectorImpl::SetUpPrinterDone, | |
227 weak_ptr_factory_.GetWeakPtr(), | |
228 base::Passed(std::move(data)))); | |
229 } | |
230 | |
231 // Called on the UI thread with the result of asking to have a printer | |
232 // configured for cups. If |printer_to_register| is non-null and we | |
skau
2017/03/11 00:00:34
nit: s/cups/CUPS/
| |
233 // successfully configured, then the printer is registered with the printers | |
234 // manager. | |
235 void SetUpPrinterDone(std::unique_ptr<SetUpPrinterData> data, | |
236 PrinterSetupResult result) { | |
237 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
238 if (result == PrinterSetupResult::SUCCESS) { | |
239 if (data->is_new) { | |
240 PrintersManagerFactory::GetForBrowserContext(profile_)->RegisterPrinter( | |
241 std::move(data->printer)); | |
242 } | |
243 if (data->hotplugged) { | |
244 // TODO(justincarlson): Pop a timed notification that says the printer | |
245 // is now available for printing. | |
246 } | |
247 } else { | |
248 // TODO(justincarlson): Pop a notification that tells the user automatic | |
249 // setup failed and offers to open the CUPS printer configuration | |
250 // settings. | |
251 DCHECK(!base::ContainsKey(failed_setup_printers_, data->device->guid())); | |
252 failed_setup_printers_.insert({data->device->guid(), *(data->printer)}); | |
253 } | |
147 } | 254 } |
148 | 255 |
149 void SetNotificationUIManagerForTesting( | 256 void SetNotificationUIManagerForTesting( |
150 NotificationUIManager* manager) override { | 257 NotificationUIManager* manager) override { |
151 LOG(FATAL) << "Not implemented for CUPS"; | 258 LOG(FATAL) << "Not implemented for CUPS"; |
152 } | 259 } |
153 | 260 |
154 void ShowUSBPrinterSetupNotification( | 261 // USB GUIDs of printers we've already dealt with. There's an inherent race |
155 scoped_refptr<device::UsbDevice> device) { | 262 // between initially querying all usb devices and receiving a notification |
156 // TODO(justincarlson) - Test this notification across a wide variety of | 263 // about a new device, so this set lets us guarantee that we handle a given |
157 // less-than-sane printers to make sure the notification text stays as | 264 // printer exactly once. |
158 // intelligible as possible. | 265 std::set<std::string> known_printers_; |
159 base::string16 printer_name = device->manufacturer_string() + | 266 |
160 base::UTF8ToUTF16(" ") + | 267 // Printers that this class failed to set up automatically. This is provided |
161 device->product_string(); | 268 // to the PrinterDiscoverer used in the settings flow to determine which |
162 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); | 269 // printers are available to be set up. This is a map from the USB GUID |
163 message_center::RichNotificationData data; | 270 // to Printer structure. |
164 data.buttons.push_back(message_center::ButtonInfo(l10n_util::GetStringUTF16( | 271 std::unordered_map<std::string, Printer> failed_setup_printers_; |
165 IDS_PRINTER_DETECTED_NOTIFICATION_SET_UP_BUTTON))); | 272 |
166 notification_.reset(new Notification( | 273 // The active ppd_provider, if any. References to ppd_provider_ are managed |
167 message_center::NOTIFICATION_TYPE_SIMPLE, | 274 // on the UI thread. |
168 l10n_util::GetStringUTF16( | 275 scoped_refptr<printing::PpdProvider> ppd_provider_; |
skau
2017/03/11 00:00:34
This member appears unused.
Carlson
2017/03/11 01:19:16
Thanks, was doing this differently before.
| |
169 IDS_PRINTER_DETECTED_NOTIFICATION_SET_UP_TITLE), // title | |
170 printer_name, // body | |
171 bundle.GetImageNamed(IDR_PRINTER_DETECTED_NOTIFICATION), // icon | |
172 message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, | |
173 kUSBPrinterFoundNotificationID), | |
174 base::string16(), // display_source | |
175 GURL(), kUSBPrinterFoundNotificationID, data, | |
176 new USBPrinterSetupNotificationDelegate(this))); | |
177 notification_->SetSystemPriority(); | |
178 command_ = ButtonCommand::SETUP; | |
179 | |
180 g_browser_process->notification_ui_manager()->Add(*notification_, profile_); | |
181 } | |
182 | |
183 void OnSetUpUSBPrinterStarted() { | |
184 notification_->set_title(l10n_util::GetStringUTF16( | |
185 IDS_PRINTER_DETECTED_NOTIFICATION_SET_UP_IN_PROGRESS_TITLE)); | |
186 notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS); | |
187 notification_->set_progress(-1); | |
188 std::vector<message_center::ButtonInfo> buttons; | |
189 buttons.push_back(message_center::ButtonInfo(l10n_util::GetStringUTF16( | |
190 IDS_PRINTER_DETECTED_NOTIFICATION_SET_UP_CANCEL_BUTTON))); | |
191 notification_->set_buttons(buttons); | |
192 command_ = ButtonCommand::CANCEL_SETUP; | |
193 g_browser_process->notification_ui_manager()->Add(*notification_, profile_); | |
194 } | |
195 | |
196 void OnSetUpUSBPrinterDone() { | |
197 notification_->set_title(l10n_util::GetStringUTF16( | |
198 IDS_PRINTER_DETECTED_NOTIFICATION_SET_UP_SUCCESS_TITLE)); | |
199 notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE); | |
200 std::vector<message_center::ButtonInfo> buttons; | |
201 buttons.push_back(message_center::ButtonInfo(l10n_util::GetStringUTF16( | |
202 IDS_PRINTER_DETECTED_NOTIFICATION_SET_UP_CLOSE_BUTTON))); | |
203 notification_->set_buttons(buttons); | |
204 command_ = ButtonCommand::CLOSE; | |
205 g_browser_process->notification_ui_manager()->Add(*notification_, profile_); | |
206 } | |
207 | |
208 void OnSetUpUSBPrinterError() { | |
209 notification_->set_title(l10n_util::GetStringUTF16( | |
210 IDS_PRINTER_DETECTED_NOTIFICATION_SET_UP_FAILED_TITLE)); | |
211 notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE); | |
212 std::vector<message_center::ButtonInfo> buttons; | |
213 buttons.push_back(message_center::ButtonInfo(l10n_util::GetStringUTF16( | |
214 IDS_PRINTER_DETECTED_NOTIFICATION_SET_UP_GET_HELP_BUTTON))); | |
215 notification_->set_buttons(buttons); | |
216 command_ = ButtonCommand::GET_HELP; | |
217 g_browser_process->notification_ui_manager()->Add(*notification_, profile_); | |
218 } | |
219 | |
220 std::unique_ptr<Notification> notification_; | |
221 ButtonCommand command_ = ButtonCommand::SETUP; | |
222 | 276 |
223 Profile* profile_; | 277 Profile* profile_; |
224 ScopedObserver<device::UsbService, device::UsbService::Observer> observer_; | 278 ScopedObserver<device::UsbService, device::UsbService::Observer> observer_; |
225 base::WeakPtrFactory<CupsPrinterDetectorImpl> weak_ptr_factory_; | 279 base::WeakPtrFactory<CupsPrinterDetectorImpl> weak_ptr_factory_; |
226 }; | 280 }; |
227 | 281 |
228 void USBPrinterSetupNotificationDelegate::ButtonClick(int button_index) { | |
229 printer_detector_->ClickOnNotificationButton(button_index); | |
230 } | |
231 | |
232 } // namespace | 282 } // namespace |
233 | 283 |
234 // static | 284 // static |
235 std::unique_ptr<PrinterDetector> PrinterDetector::CreateCups(Profile* profile) { | 285 std::unique_ptr<PrinterDetector> PrinterDetector::CreateCups(Profile* profile) { |
236 return base::MakeUnique<CupsPrinterDetectorImpl>(profile); | 286 return base::MakeUnique<CupsPrinterDetectorImpl>(profile); |
237 } | 287 } |
238 | 288 |
239 } // namespace chromeos | 289 } // namespace chromeos |
OLD | NEW |