Chromium Code Reviews| 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" |
|
tbarzic
2017/03/15 18:43:42
this is not needed anymore, right?
Carlson
2017/03/15 23:06:16
Done.
| |
| 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 |
|
tbarzic
2017/03/15 18:43:42
This comment could be a lot shorter :)
E.g.
Aggreg
Carlson
2017/03/15 23:06:16
Done.
| |
| 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; |
| 63 }; | |
| 65 | 64 |
| 66 bool HasClickedListener() override { return true; } | 65 // Given a usb device, guess the make and model for a driver lookup. |
|
tbarzic
2017/03/15 18:43:42
nit: s/guess/guesses/
Carlson
2017/03/15 23:06:16
Done.
| |
| 67 | 66 // |
| 68 private: | 67 // TODO(justincarlson): Possibly go deeper and query the IEEE1284 fields |
| 69 ~USBPrinterSetupNotificationDelegate() override = default; | 68 // for make and model if we determine those are more likely to contain |
| 70 | 69 // what we want. |
| 71 CupsPrinterDetectorImpl* printer_detector_; | 70 std::string GuessEffectiveMakeAndModel(const device::UsbDevice& device) { |
| 72 | 71 return base::UTF16ToUTF8(device.manufacturer_string()) + " " + |
| 73 DISALLOW_COPY_AND_ASSIGN(USBPrinterSetupNotificationDelegate); | 72 base::UTF16ToUTF8(device.product_string()); |
| 74 }; | 73 } |
| 75 | 74 |
| 76 // The PrinterDetector that drives the flow for setting up a USB printer to use | 75 // The PrinterDetector that drives the flow for setting up a USB printer to use |
| 77 // CUPS backend. | 76 // CUPS backend. |
| 78 class CupsPrinterDetectorImpl : public PrinterDetector, | 77 class CupsPrinterDetectorImpl : public PrinterDetector, |
| 79 public device::UsbService::Observer { | 78 public device::UsbService::Observer { |
| 80 public: | 79 public: |
| 81 explicit CupsPrinterDetectorImpl(Profile* profile) | 80 explicit CupsPrinterDetectorImpl(Profile* profile) |
| 82 : profile_(profile), observer_(this), weak_ptr_factory_(this) { | 81 : profile_(profile), observer_(this), weak_ptr_factory_(this) { |
| 83 extensions::ExtensionSystem::Get(profile)->ready().Post( | |
| 84 FROM_HERE, base::Bind(&CupsPrinterDetectorImpl::Initialize, | |
| 85 weak_ptr_factory_.GetWeakPtr())); | |
| 86 } | |
| 87 ~CupsPrinterDetectorImpl() override = default; | |
| 88 | |
| 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: | |
| 113 // Action that should be performed when a notification button is clicked. | |
| 114 enum class ButtonCommand { | |
| 115 SETUP, | |
| 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 } |
| 92 device::UsbService* usb_service = | |
| 93 device::DeviceClient::Get()->GetUsbService(); | |
| 94 if (usb_service) { | |
| 95 observer_.Add(usb_service); | |
| 96 usb_service->GetDevices(base::Bind(&CupsPrinterDetectorImpl::OnGetDevices, | |
| 97 weak_ptr_factory_.GetWeakPtr())); | |
| 98 } | |
| 99 } | |
| 100 ~CupsPrinterDetectorImpl() override = default; | |
| 131 | 101 |
| 132 device::UsbDeviceFilter printer_filter; | 102 private: |
| 133 printer_filter.interface_class = kPrinterInterfaceClass; | 103 // Callback for initial enumeration of usb devices. UsbService invokes |
| 134 if (!printer_filter.Matches(device)) | 104 // this on the UI thread. |
| 135 return; | 105 void OnGetDevices( |
| 136 | 106 const std::vector<scoped_refptr<device::UsbDevice>>& devices) { |
| 137 ShowUSBPrinterSetupNotification(device); | 107 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 108 for (const auto& device : devices) { | |
| 109 MaybeSetUpDevice(device, false); | |
| 110 } | |
| 138 } | 111 } |
| 139 | 112 |
| 140 // Initializes the printer detector. | 113 // UsbService::observer override. This runs on the UI thread. |
| 141 void Initialize() { | 114 void OnDeviceAdded(scoped_refptr<device::UsbDevice> device) override { |
| 142 device::UsbService* usb_service = | 115 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 143 device::DeviceClient::Get()->GetUsbService(); | 116 MaybeSetUpDevice(device, true); |
| 144 if (!usb_service) | 117 } |
| 118 | |
| 119 // UsbService::observer override. This runs on the UI thread. | |
| 120 void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) override { | |
| 121 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 122 if (!UsbDeviceIsPrinter(device)) { | |
| 145 return; | 123 return; |
| 146 observer_.Add(usb_service); | 124 } |
| 125 known_printers_.erase(device->guid()); | |
| 126 | |
| 127 // If this printer appears in the list of printers we've failed to set up, | |
| 128 // remove it. | |
| 129 failed_setup_printers_.erase(device->guid()); | |
| 130 } | |
| 131 | |
| 132 // This is called on the UI thread. | |
| 133 void MaybeSetUpDevice(scoped_refptr<device::UsbDevice> device, | |
| 134 bool hotplugged) { | |
| 135 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 136 | |
| 137 if (!UsbDeviceIsPrinter(device) || | |
| 138 base::ContainsKey(known_printers_, device->guid())) { | |
| 139 return; | |
| 140 } | |
| 141 known_printers_.insert(device->guid()); | |
| 142 | |
| 143 auto data = base::MakeUnique<SetUpPrinterData>(); | |
| 144 data->configurer = PrinterConfigurer::Create(profile_); | |
| 145 data->printer = base::MakeUnique<Printer>(); | |
|
tbarzic
2017/03/15 18:43:42
This still seems a little convoluted :/
Could we i
Carlson
2017/03/15 23:06:16
Took some of these ideas to try to clarify, but di
tbarzic
2017/03/16 04:11:29
looks good
| |
| 146 data->device = device; | |
| 147 data->is_new = true; | |
| 148 data->hotplugged = hotplugged; | |
| 149 if (!UsbDeviceToPrinter(*device, data->printer.get())) { | |
| 150 LOG(ERROR) | |
|
tbarzic
2017/03/15 18:43:42
UsbDeviceToPrinter already logs an error
Carlson
2017/03/15 23:06:16
Done.
| |
| 151 << "Failed to convert usb device to printer, abandoning setup. " | |
| 152 << "Usb device details follow:"; | |
| 153 LOG(ERROR) << UsbPrinterDeviceDetailsAsString(*device); | |
| 154 return; | |
| 155 } | |
| 156 // TODO(justincarlson): add a GetPrinterByURI to PrintersManager. | |
| 157 // https://crbug.com/700602 | |
| 158 auto existing_printers = | |
| 159 PrintersManagerFactory::GetForBrowserContext(profile_)->GetPrinters(); | |
| 160 for (std::unique_ptr<Printer>& printer : existing_printers) { | |
| 161 if (printer->uri() == data->printer->uri()) { | |
| 162 // Found a match, so use the existing configuration. | |
| 163 *(data->printer) = *printer; | |
| 164 data->is_new = false; | |
| 165 OnPrinterResolved(std::move(data)); | |
| 166 return; | |
| 167 } | |
| 168 } | |
| 169 | |
| 170 // It's not a device we know about. First we see if we can get an exact | |
| 171 // driver match based on USB ids. | |
| 172 // | |
| 173 // TODO(justincarlson): Add a notification that we are attempting to set up | |
| 174 // this printer at this point. | |
| 175 scoped_refptr<PpdProvider> ppd_provider = | |
| 176 printing::CreateProvider(profile_); | |
| 177 ppd_provider->ResolveUsbIds( | |
| 178 device->vendor_id(), device->product_id(), | |
| 179 base::Bind(&CupsPrinterDetectorImpl::ResolveUsbIdsDone, | |
| 180 weak_ptr_factory_.GetWeakPtr(), | |
| 181 base::Passed(std::move(data)))); | |
| 182 } | |
| 183 | |
| 184 void OnPrinterResolved(std::unique_ptr<SetUpPrinterData> data) { | |
| 185 // Copy fields that will be invalidated by std::move. | |
| 186 auto* configurer_tmp = data->configurer.get(); | |
| 187 const Printer& printer_tmp = *(data->printer); | |
| 188 // off to the configurer. | |
| 189 configurer_tmp->SetUpPrinter( | |
| 190 printer_tmp, base::Bind(&CupsPrinterDetectorImpl::SetUpPrinterDone, | |
| 191 weak_ptr_factory_.GetWeakPtr(), | |
| 192 base::Passed(std::move(data)))); | |
| 193 } | |
| 194 | |
| 195 // Called when the query for a driver based on usb ids completes. | |
| 196 void ResolveUsbIdsDone(std::unique_ptr<SetUpPrinterData> data, | |
| 197 PpdProvider::CallbackResultCode result, | |
| 198 const std::string& effective_make_and_model) { | |
| 199 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 200 if (result == PpdProvider::SUCCESS) { | |
| 201 // Got something based on usb ids. Go with it. | |
| 202 data->printer->mutable_ppd_reference()->effective_make_and_model = | |
| 203 effective_make_and_model; | |
| 204 } else { | |
| 205 // Couldn't figure this printer out based on usb ids, fall back to | |
| 206 // guessing the make/model string from what the USB system reports. | |
| 207 // | |
| 208 // TODO(justincarlson): Consider adding a mechanism for aggregating data | |
| 209 // about which usb devices are in the wild but unsupported? | |
| 210 data->printer->mutable_ppd_reference()->effective_make_and_model = | |
| 211 GuessEffectiveMakeAndModel(*data->device); | |
| 212 } | |
| 213 OnPrinterResolved(std::move(data)); | |
|
tbarzic
2017/03/15 18:43:42
I wonder if it would make sense to register new pr
Carlson
2017/03/15 23:06:16
There's a reasonable argument to be made for that,
tbarzic
2017/03/16 04:11:28
sounds good
| |
| 214 } | |
| 215 | |
| 216 // Called on the UI thread with the result of asking to have a printer | |
| 217 // configured for CUPS. If |printer_to_register| is non-null and we | |
| 218 // successfully configured, then the printer is registered with the printers | |
| 219 // manager. | |
| 220 void SetUpPrinterDone(std::unique_ptr<SetUpPrinterData> data, | |
| 221 PrinterSetupResult result) { | |
| 222 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 223 if (result == PrinterSetupResult::SUCCESS) { | |
| 224 if (data->is_new) { | |
| 225 PrintersManagerFactory::GetForBrowserContext(profile_)->RegisterPrinter( | |
| 226 std::move(data->printer)); | |
| 227 } | |
| 228 if (data->hotplugged) { | |
| 229 // TODO(justincarlson): Pop a timed notification that says the printer | |
| 230 // is now available for printing. | |
| 231 } | |
| 232 } else { | |
| 233 // TODO(justincarlson): Pop a notification that tells the user automatic | |
| 234 // setup failed and offers to open the CUPS printer configuration | |
| 235 // settings. | |
| 236 DCHECK(!base::ContainsKey(failed_setup_printers_, data->device->guid())); | |
| 237 failed_setup_printers_.insert({data->device->guid(), *(data->printer)}); | |
| 238 } | |
| 147 } | 239 } |
| 148 | 240 |
| 149 void SetNotificationUIManagerForTesting( | 241 void SetNotificationUIManagerForTesting( |
| 150 NotificationUIManager* manager) override { | 242 NotificationUIManager* manager) override { |
| 151 LOG(FATAL) << "Not implemented for CUPS"; | 243 LOG(FATAL) << "Not implemented for CUPS"; |
| 152 } | 244 } |
| 153 | 245 |
| 154 void ShowUSBPrinterSetupNotification( | 246 // USB GUIDs of printers we've already dealt with. There's an inherent race |
| 155 scoped_refptr<device::UsbDevice> device) { | 247 // between initially querying all usb devices and receiving a notification |
| 156 // TODO(justincarlson) - Test this notification across a wide variety of | 248 // 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 | 249 // printer exactly once. |
| 158 // intelligible as possible. | 250 std::set<std::string> known_printers_; |
| 159 base::string16 printer_name = device->manufacturer_string() + | |
| 160 base::UTF8ToUTF16(" ") + | |
| 161 device->product_string(); | |
| 162 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); | |
| 163 message_center::RichNotificationData data; | |
| 164 data.buttons.push_back(message_center::ButtonInfo(l10n_util::GetStringUTF16( | |
| 165 IDS_PRINTER_DETECTED_NOTIFICATION_SET_UP_BUTTON))); | |
| 166 notification_.reset(new Notification( | |
| 167 message_center::NOTIFICATION_TYPE_SIMPLE, | |
| 168 l10n_util::GetStringUTF16( | |
| 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 | 251 |
| 180 g_browser_process->notification_ui_manager()->Add(*notification_, profile_); | 252 // Printers that this class failed to set up automatically. This is provided |
| 181 } | 253 // to the PrinterDiscoverer used in the settings flow to determine which |
| 182 | 254 // printers are available to be set up. This is a map from the USB GUID |
| 183 void OnSetUpUSBPrinterStarted() { | 255 // to Printer structure. |
| 184 notification_->set_title(l10n_util::GetStringUTF16( | 256 std::unordered_map<std::string, Printer> failed_setup_printers_; |
| 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 | 257 |
| 223 Profile* profile_; | 258 Profile* profile_; |
| 224 ScopedObserver<device::UsbService, device::UsbService::Observer> observer_; | 259 ScopedObserver<device::UsbService, device::UsbService::Observer> observer_; |
| 225 base::WeakPtrFactory<CupsPrinterDetectorImpl> weak_ptr_factory_; | 260 base::WeakPtrFactory<CupsPrinterDetectorImpl> weak_ptr_factory_; |
| 226 }; | 261 }; |
| 227 | 262 |
| 228 void USBPrinterSetupNotificationDelegate::ButtonClick(int button_index) { | |
| 229 printer_detector_->ClickOnNotificationButton(button_index); | |
| 230 } | |
| 231 | |
| 232 } // namespace | 263 } // namespace |
| 233 | 264 |
| 234 // static | 265 // static |
| 235 std::unique_ptr<PrinterDetector> PrinterDetector::CreateCups(Profile* profile) { | 266 std::unique_ptr<PrinterDetector> PrinterDetector::CreateCups(Profile* profile) { |
| 236 return base::MakeUnique<CupsPrinterDetectorImpl>(profile); | 267 return base::MakeUnique<CupsPrinterDetectorImpl>(profile); |
| 237 } | 268 } |
| 238 | 269 |
| 239 } // namespace chromeos | 270 } // namespace chromeos |
| OLD | NEW |