diff options
-rw-r--r-- | chrome/app/generated_resources.grd | 17 | ||||
-rw-r--r-- | chrome/app/theme/default_100_percent/cros/printer_notification.png | bin | 0 -> 214 bytes | |||
-rw-r--r-- | chrome/app/theme/default_200_percent/cros/printer_notification.png | bin | 0 -> 365 bytes | |||
-rw-r--r-- | chrome/app/theme/theme_resources.grd | 3 | ||||
-rw-r--r-- | chrome/browser/chromeos/dbus/printer_service_provider.cc | 247 | ||||
-rw-r--r-- | chrome/browser/chromeos/dbus/printer_service_provider.h | 8 | ||||
-rw-r--r-- | chrome/browser/chromeos/dbus/printer_service_provider_unittest.cc | 271 | ||||
-rw-r--r-- | chrome/browser/chromeos/profiles/profile_helper.h | 1 | ||||
-rw-r--r-- | chromeos/chromeos_switches.cc | 6 | ||||
-rw-r--r-- | chromeos/chromeos_switches.h | 1 |
10 files changed, 541 insertions, 13 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 213503f..b839372 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -15901,6 +15901,23 @@ Do you accept? <message name="IDS_ENABLE_INVALID_CERT_COLLECTION_DESCRIPTION" desc="Description of the 'Enable invalid certificate collection' flag."> Allows users to opt in to the collection of invalid TLS/SSL certificate chains. </message> + + <!-- Printer detected notification --> + <if expr="chromeos"> + <message name="IDS_PRINTER_DETECTED_NOTIFICATION_TITLE" desc="Title for notification shown to the user when a printer gets plugged in to a Chrome OS device."> + Printer from <ph name="VENDOR_NAME">$1<ex>Google</ex></ph> detected + </message> + <message name="IDS_PRINTER_DETECTED_NOTIFICATION_TITLE_UNKNOWN_VENDOR" desc="Title for notification shown to the user when a printer gets plugged in to a Chrome OS device in the case the printer manufacturer name is unknown."> + Printer detected + </message> + <message name="IDS_PRINTER_DETECTED_NOTIFICATION_NO_PRINT_APP_BODY" desc="Content for notification shown to the user when a printer gets plugged in to a Chrome OS device if the active user does not have an app that supports the printer installed."> + Click to find a print app to use this printer. + </message> + <message name="IDS_PRINTER_DETECTED_NOTIFICATION_PRINT_APP_FOUND_BODY" desc="Content for notification shown to the user when a printer gets plugged in to a Chrome OS device if the active user already has a print app that supports the printer installed."> + Your printer is ready. + </message> + </if> + </messages> </release> </grit> diff --git a/chrome/app/theme/default_100_percent/cros/printer_notification.png b/chrome/app/theme/default_100_percent/cros/printer_notification.png Binary files differnew file mode 100644 index 0000000..6e14c55 --- /dev/null +++ b/chrome/app/theme/default_100_percent/cros/printer_notification.png diff --git a/chrome/app/theme/default_200_percent/cros/printer_notification.png b/chrome/app/theme/default_200_percent/cros/printer_notification.png Binary files differnew file mode 100644 index 0000000..2b1da79 --- /dev/null +++ b/chrome/app/theme/default_200_percent/cros/printer_notification.png diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index a1f7fd8..d4a1323 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd @@ -633,6 +633,9 @@ <structure type="chrome_scaled_image" name="IDR_PHONE_FAVICON" file="common/favicon_phone.png" /> <structure type="chrome_scaled_image" name="IDR_PLUGINS_FAVICON" file="common/favicon_extensions.png" /> <structure type="chrome_scaled_image" name="IDR_PRERENDER" file="common/prerender_succeed_icon.png" /> + <if expr="chromeos"> + <structure type="chrome_scaled_image" name="IDR_PRINTER_NOTIFICATION" file="cros/printer_notification.png" /> + </if> <if expr="not _google_chrome"> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO" file="chromium/product_logo.png" /> <structure type="chrome_scaled_image" name="IDR_PRODUCT_LOGO_16" file="chromium/product_logo_16.png" /> diff --git a/chrome/browser/chromeos/dbus/printer_service_provider.cc b/chrome/browser/chromeos/dbus/printer_service_provider.cc index c70305e..6310dd2 100644 --- a/chrome/browser/chromeos/dbus/printer_service_provider.cc +++ b/chrome/browser/chromeos/dbus/printer_service_provider.cc @@ -4,14 +4,28 @@ #include "chrome/browser/chromeos/dbus/printer_service_provider.h" +#include <stdint.h> + +#include <limits> + #include "ash/session/session_state_delegate.h" #include "ash/shell.h" #include "ash/wm/window_util.h" #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/command_line.h" +#include "base/memory/scoped_ptr.h" #include "base/metrics/histogram.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" #include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" #include "base/sys_info.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/notifications/notification.h" +#include "chrome/browser/notifications/notification_delegate.h" +#include "chrome/browser/notifications/notification_ui_manager.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_tabstrip.h" @@ -20,19 +34,39 @@ #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_version_info.h" +#include "chrome/grit/generated_resources.h" +#include "chromeos/chromeos_switches.h" +#include "components/user_manager/user.h" +#include "components/user_manager/user_manager.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h" #include "dbus/bus.h" #include "dbus/exported_object.h" #include "dbus/message.h" +#include "device/usb/usb_ids.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/common/extension.h" +#include "extensions/common/extension_set.h" +#include "extensions/common/permissions/api_permission.h" +#include "extensions/common/permissions/permissions_data.h" +#include "extensions/common/permissions/usb_device_permission.h" +#include "grit/theme_resources.h" #include "net/base/escape.h" #include "third_party/cros_system_api/dbus/service_constants.h" #include "ui/aura/window.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" namespace { const char kPrinterAdded[] = "PrinterAdded"; +const char kPrinterProviderFoundNotificationID[] = + "chrome://settings/printer/printer_app_found"; + +const char kNoPrinterProviderNotificationID[] = + "chrome://settings/printer/no_printer_app"; + enum PrinterServiceEvent { PRINTER_ADDED, PAGE_DISPLAYED, @@ -55,7 +89,16 @@ Browser* ActivateAndGetBrowserForUrl(GURL url) { return it.browser(); } } - return NULL; + return nullptr; +} + +bool HexStringToUInt16(const std::string& input, uint16* output) { + uint32 output_uint = 0; + if (!base::HexStringToUInt(input, &output_uint) || + output_uint > std::numeric_limits<uint16>::max()) + return false; + *output = static_cast<uint16>(output_uint); + return true; } void FindOrOpenCloudPrintPage(const std::string& /* vendor */, @@ -84,12 +127,173 @@ void FindOrOpenCloudPrintPage(const std::string& /* vendor */, } } +base::string16 GetNotificationTitle(uint16 vendor_id, uint16 product_id) { + const char* vendor_name = device::UsbIds::GetVendorName(vendor_id); + if (vendor_name) { + return l10n_util::GetStringFUTF16(IDS_PRINTER_DETECTED_NOTIFICATION_TITLE, + base::UTF8ToUTF16(vendor_name)); + } else { + return l10n_util::GetStringUTF16( + IDS_PRINTER_DETECTED_NOTIFICATION_TITLE_UNKNOWN_VENDOR); + } +} + +std::string GetNotificationTag(const std::string& vendor_id, + const std::string& product_id) { + return vendor_id + ":" + product_id; +} + +// Checks if there is an enabled extension with printerProvider permission and +// usbDevices persmission for the USB (vendor_id, product_id) pair. +bool HasAppThatSupportsPrinter(Profile* profile, + uint16 vendor_id, + uint16 product_id) { + const extensions::ExtensionSet& enabled_extensions = + extensions::ExtensionRegistry::Get(profile)->enabled_extensions(); + for (const auto& extension : enabled_extensions) { + if (!extension->permissions_data() || + !extension->permissions_data()->HasAPIPermission( + extensions::APIPermission::kPrinterProvider) || + !extension->permissions_data()->HasAPIPermission( + extensions::APIPermission::kUsb)) { + continue; + } + + extensions::UsbDevicePermission::CheckParam param( + vendor_id, product_id, + extensions::UsbDevicePermissionData::UNSPECIFIED_INTERFACE); + if (extension->permissions_data()->CheckAPIPermissionWithParam( + extensions::APIPermission::kUsbDevice, ¶m)) { + return true; + } + } + return false; +} + +// Delegate for notification shown when a printer provider app for the plugged +// in printer is found. +class PrinterProviderExistsNotificationDelegate : public NotificationDelegate { + public: + PrinterProviderExistsNotificationDelegate(const std::string& vendor_id, + const std::string& product_id) + : vendor_id_(vendor_id), product_id_(product_id) {} + + std::string id() const override { + return "system.printer.printer_provider_exists/" + + GetNotificationTag(vendor_id_, product_id_); + } + + private: + ~PrinterProviderExistsNotificationDelegate() override = default; + + const std::string vendor_id_; + const std::string product_id_; + + DISALLOW_COPY_AND_ASSIGN(PrinterProviderExistsNotificationDelegate); +}; + +// Delegate for notification shown when there are no printer provider apps that +// support the plugged in printer found. +// The notification is clickable, and clicking it is supposed to launch +// Chrome Web Store widget listing apps that can support the plugged in printer. +// (not implemented yet). +class SearchPrinterAppNotificationDelegate : public NotificationDelegate { + public: + SearchPrinterAppNotificationDelegate(const std::string& vendor_id, + const std::string& product_id) + : vendor_id_(vendor_id), product_id_(product_id) {} + + std::string id() const override { + return "system.printer.no_printer_provider_found/" + + GetNotificationTag(vendor_id_, product_id_); + } + bool HasClickedListener() override { return true; } + + void Click() override { + // TODO(tbarzic): Implement this (http://crbug.com/439448). + } + + private: + ~SearchPrinterAppNotificationDelegate() override = default; + + std::string vendor_id_; + std::string product_id_; + + DISALLOW_COPY_AND_ASSIGN(SearchPrinterAppNotificationDelegate); +}; + +// Shows a notification for a plugged in printer. +// If there is a printerProvider app that handles the printer's USB (vendor_id, +// product_id) pair, the notification informs the user that the printer is ready +// to be used, otherwise it offers the user to search the Chrome Web Store for +// an app that can handle the printer. +void ShowPrinterPluggedNotification( + NotificationUIManager* notification_ui_manager, + const std::string& vendor_id_str, + const std::string& product_id_str) { + uint16 vendor_id = 0; + uint16 product_id = 0; + if (!HexStringToUInt16(vendor_id_str, &vendor_id) || + !HexStringToUInt16(product_id_str, &product_id)) { + LOG(WARNING) << "Invalid USB ID " << vendor_id_str << ":" << product_id_str; + return; + } + + const user_manager::User* user = + user_manager::UserManager::Get() + ? user_manager::UserManager::Get()->GetActiveUser() + : nullptr; + if (!user || !user->HasGaiaAccount()) + return; + + Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user); + if (!profile) + return; + + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); + scoped_ptr<Notification> notification; + + if (HasAppThatSupportsPrinter(profile, vendor_id, product_id)) { + notification.reset(new Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + GURL(kPrinterProviderFoundNotificationID), + GetNotificationTitle(vendor_id, product_id), + l10n_util::GetStringUTF16( + IDS_PRINTER_DETECTED_NOTIFICATION_PRINT_APP_FOUND_BODY), + bundle.GetImageNamed(IDR_PRINTER_NOTIFICATION), + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, + kPrinterProviderFoundNotificationID), + base::string16(), GetNotificationTag(vendor_id_str, product_id_str), + message_center::RichNotificationData(), + new PrinterProviderExistsNotificationDelegate(vendor_id_str, + product_id_str))); + } else { + message_center::RichNotificationData options; + options.clickable = true; + notification.reset(new Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + GURL(kNoPrinterProviderNotificationID), + GetNotificationTitle(vendor_id, product_id), + l10n_util::GetStringUTF16( + IDS_PRINTER_DETECTED_NOTIFICATION_NO_PRINT_APP_BODY), + bundle.GetImageNamed(IDR_PRINTER_NOTIFICATION), + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, + kNoPrinterProviderNotificationID), + base::string16(), GetNotificationTag(vendor_id_str, product_id_str), + options, new SearchPrinterAppNotificationDelegate(vendor_id_str, + product_id_str))); + } + + notification->SetSystemPriority(); + notification_ui_manager->Add(*notification, profile); +} + } // namespace namespace chromeos { PrinterServiceProvider::PrinterServiceProvider() - : weak_ptr_factory_(this) { + : notification_ui_manager_(nullptr), weak_ptr_factory_(this) { } PrinterServiceProvider::~PrinterServiceProvider() { @@ -109,6 +313,11 @@ void PrinterServiceProvider::Start( weak_ptr_factory_.GetWeakPtr())); } +void PrinterServiceProvider::SetNotificationUIManagerForTesting( + NotificationUIManager* manager) { + notification_ui_manager_ = manager; +} + void PrinterServiceProvider::OnExported( const std::string& interface_name, const std::string& method_name, @@ -132,6 +341,28 @@ void PrinterServiceProvider::PrinterAdded( dbus::ExportedObject::ResponseSender response_sender) { DVLOG(1) << "PrinterAdded " << method_call->ToString(); + dbus::MessageReader reader(method_call); + + std::string vendor_id; + reader.PopString(&vendor_id); + StringToUpperASCII(&vendor_id); + + std::string product_id; + reader.PopString(&product_id); + StringToUpperASCII(&product_id); + + // Send an empty response. + response_sender.Run(dbus::Response::FromMethodCall(method_call)); + + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnablePrinterAppSearch)) { + ShowPrinterPluggedNotification( + notification_ui_manager_ ? notification_ui_manager_ + : g_browser_process->notification_ui_manager(), + vendor_id, product_id); + return; + } + // Disable showing Cloudprint help on canary and dev channel, as these have // support for printerProvider API. // TODO(tbarzic): Remove this and offer the user to search for an extension @@ -141,17 +372,7 @@ void PrinterServiceProvider::PrinterAdded( chrome::VersionInfo::GetChannel() <= chrome::VersionInfo::CHANNEL_DEV) return; - dbus::MessageReader reader(method_call); - std::string vendor; - std::string product; - // Don't check for error, parameters are optional. If some string is empty - // web server will show generic help page. - reader.PopString(&vendor); - reader.PopString(&product); - ShowCloudPrintHelp(vendor, product); - - // Send an empty response. - response_sender.Run(dbus::Response::FromMethodCall(method_call)); + ShowCloudPrintHelp(vendor_id, product_id); } } // namespace chromeos diff --git a/chrome/browser/chromeos/dbus/printer_service_provider.h b/chrome/browser/chromeos/dbus/printer_service_provider.h index 19163f2..68c1cff 100644 --- a/chrome/browser/chromeos/dbus/printer_service_provider.h +++ b/chrome/browser/chromeos/dbus/printer_service_provider.h @@ -11,6 +11,8 @@ #include "chromeos/dbus/services/cros_dbus_service.h" #include "dbus/exported_object.h" +class NotificationUIManager; + namespace dbus { class MethodCall; class Response; @@ -57,6 +59,10 @@ class PrinterServiceProvider const std::string& product); private: + friend class PrinterServiceProviderAppSearchEnabledTest; + + void SetNotificationUIManagerForTesting(NotificationUIManager* manager); + // Called from ExportedObject, when PrinterAdded() is exported as // a D-Bus method, or failed to be exported. void OnExported(const std::string& interface_name, @@ -68,6 +74,8 @@ class PrinterServiceProvider void PrinterAdded(dbus::MethodCall* method_call, dbus::ExportedObject::ResponseSender response_sender); + NotificationUIManager* notification_ui_manager_; + scoped_refptr<dbus::ExportedObject> exported_object_; base::WeakPtrFactory<PrinterServiceProvider> weak_ptr_factory_; diff --git a/chrome/browser/chromeos/dbus/printer_service_provider_unittest.cc b/chrome/browser/chromeos/dbus/printer_service_provider_unittest.cc index ae24e5c..7dd3e99 100644 --- a/chrome/browser/chromeos/dbus/printer_service_provider_unittest.cc +++ b/chrome/browser/chromeos/dbus/printer_service_provider_unittest.cc @@ -4,14 +4,35 @@ #include "chrome/browser/chromeos/dbus/printer_service_provider.h" +#include "base/command_line.h" +#include "base/strings/stringprintf.h" +#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#include "chrome/browser/notifications/notification.h" +#include "chrome/browser/notifications/notification_test_util.h" +#include "chrome/browser/notifications/notification_ui_manager.h" +#include "chrome/test/base/testing_profile.h" +#include "chromeos/chromeos_switches.h" #include "chromeos/dbus/services/service_provider_test_helper.h" +#include "components/user_manager/fake_user_manager.h" #include "dbus/message.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/common/extension_builder.h" +#include "extensions/common/value_builder.h" #include "third_party/cros_system_api/dbus/service_constants.h" namespace chromeos { const char kPrinterAdded[] = "PrinterAdded"; +const char kTestUserId[] = "test_user"; + +const char kPrinterAppExistsDelegateIDTemplate[] = + "system.printer.printer_provider_exists/%s:%s"; + +const char kPrinterAppNotFoundDelegateIDTemplate[] = + "system.printer.no_printer_provider_found/%s:%s"; + class MockPrinterServiceProvider : public PrinterServiceProvider { public: MOCK_METHOD2(ShowCloudPrintHelp, @@ -31,6 +52,96 @@ class PrinterServiceProviderTest : public testing::Test { ServiceProviderTestHelper test_helper_; }; +class PrinterServiceProviderAppSearchEnabledTest : public testing::Test { + public: + PrinterServiceProviderAppSearchEnabledTest() + : user_manager_(new user_manager::FakeUserManager()), + user_manager_enabler_(user_manager_) {} + + ~PrinterServiceProviderAppSearchEnabledTest() override = default; + + void SetUp() override { + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnablePrinterAppSearch); + EXPECT_CALL(service_provider_, ShowCloudPrintHelp(testing::_, testing::_)) + .Times(0); + service_provider_.SetNotificationUIManagerForTesting( + ¬ification_ui_manager_); + } + + protected: + void AddTestUser() { + const user_manager::User* user = user_manager_->AddUser(kTestUserId); + profile_.set_profile_name(kTestUserId); + chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting( + user, &profile_); + } + + bool InvokePrinterAdded(const std::string& vendor_id, + const std::string& product_id, + std::string* error) { + *error = std::string(); + test_helper_.SetUp(kPrinterAdded, &service_provider_); + + dbus::MethodCall method_call(kLibCrosServiceInterface, kPrinterAdded); + dbus::MessageWriter writer(&method_call); + writer.AppendString(vendor_id); + writer.AppendString(product_id); + + // Call the PrinterAdded method. + scoped_ptr<dbus::Response> response(test_helper_.CallMethod(&method_call)); + + // An empty response should be returned. + bool success = true; + if (response.get()) { + dbus::MessageReader reader(response.get()); + if (reader.HasMoreData()) { + *error = "Non empty response"; + success = false; + } + } else { + *error = "No response."; + success = false; + } + + // Tear down the test helper so it can be reused in the test. + test_helper_.TearDown(); + return success; + } + + // Creates a test extension with the provided permissions. + scoped_refptr<extensions::Extension> CreateTestExtension( + extensions::ListBuilder* permissions_builder) { + return extensions::ExtensionBuilder() + .SetID("fake_extension_id") + .SetManifest( + extensions::DictionaryBuilder() + .Set("name", "Printer provider extension") + .Set("manifest_version", 2) + .Set("version", "1.0") + // Needed to enable usb API. + .Set("app", + extensions::DictionaryBuilder().Set( + "background", + extensions::DictionaryBuilder().Set( + "scripts", + extensions::ListBuilder().Append("bg.js")))) + .Set("permissions", *permissions_builder)) + .Build(); + } + + StubNotificationUIManager notification_ui_manager_; + TestingProfile profile_; + user_manager::FakeUserManager* user_manager_; + chromeos::ScopedUserManagerEnabler user_manager_enabler_; + + MockPrinterServiceProvider service_provider_; + ServiceProviderTestHelper test_helper_; + + private: + DISALLOW_COPY_AND_ASSIGN(PrinterServiceProviderAppSearchEnabledTest); +}; + TEST_F(PrinterServiceProviderTest, ShowCloudPrintHelp) { dbus::MethodCall method_call(kLibCrosServiceInterface, kPrinterAdded); dbus::MessageWriter writer(&method_call); @@ -49,5 +160,165 @@ TEST_F(PrinterServiceProviderTest, ShowCloudPrintHelp) { ASSERT_FALSE(reader.HasMoreData()); } +TEST_F(PrinterServiceProviderAppSearchEnabledTest, ShowFindAppNotification) { + AddTestUser(); + + std::string error; + ASSERT_TRUE(InvokePrinterAdded("123", "456", &error)) << error; + + ASSERT_EQ(1u, notification_ui_manager_.GetNotificationCount()); + const Notification& notification = + notification_ui_manager_.GetNotificationAt(0); + EXPECT_EQ("123:456", notification.tag()); + EXPECT_EQ( + base::StringPrintf(kPrinterAppNotFoundDelegateIDTemplate, "123", "456"), + notification.delegate_id()); +} + +TEST_F(PrinterServiceProviderAppSearchEnabledTest, ShowAppFoundNotification) { + AddTestUser(); + + scoped_refptr<extensions::Extension> extension = CreateTestExtension( + &extensions::ListBuilder() + .Append("usb") + .Append("printerProvider") + .Append(extensions::DictionaryBuilder().Set( + "usbDevices", extensions::ListBuilder().Append( + extensions::DictionaryBuilder() + .Set("vendorId", 0x123) + .Set("productId", 0x456))))); + ASSERT_TRUE( + extensions::ExtensionRegistry::Get(&profile_)->AddEnabled(extension)); + + std::string error; + ASSERT_TRUE(InvokePrinterAdded("123", "456", &error)) << error; + + ASSERT_EQ(1u, notification_ui_manager_.GetNotificationCount()); + const Notification& notification = + notification_ui_manager_.GetNotificationAt(0); + EXPECT_EQ("123:456", notification.tag()); + EXPECT_EQ( + base::StringPrintf(kPrinterAppExistsDelegateIDTemplate, "123", "456"), + notification.delegate_id()); +} + +TEST_F(PrinterServiceProviderAppSearchEnabledTest, + UsbHandlerExists_NotPrinterProvider) { + AddTestUser(); + + scoped_refptr<extensions::Extension> extension = + CreateTestExtension(&extensions::ListBuilder().Append("usb").Append( + extensions::DictionaryBuilder().Set( + "usbDevices", + extensions::ListBuilder().Append(extensions::DictionaryBuilder() + .Set("vendorId", 0x123) + .Set("productId", 0xf56))))); + ASSERT_TRUE( + extensions::ExtensionRegistry::Get(&profile_)->AddEnabled(extension)); + + std::string error; + ASSERT_TRUE(InvokePrinterAdded("123", "f56", &error)) << error; + + ASSERT_EQ(1u, notification_ui_manager_.GetNotificationCount()); + const Notification& notification = + notification_ui_manager_.GetNotificationAt(0); + EXPECT_EQ("123:F56", notification.tag()); + EXPECT_EQ( + base::StringPrintf(kPrinterAppNotFoundDelegateIDTemplate, "123", "F56"), + notification.delegate_id()); +} + +TEST_F(PrinterServiceProviderAppSearchEnabledTest, + PrinterProvider_DifferentUsbProductId) { + AddTestUser(); + + scoped_refptr<extensions::Extension> extension = CreateTestExtension( + &extensions::ListBuilder() + .Append("usb") + .Append("printerProvider") + .Append(extensions::DictionaryBuilder().Set( + "usbDevices", extensions::ListBuilder().Append( + extensions::DictionaryBuilder() + .Set("vendorId", 0x123) + .Set("productId", 0x001))))); + ASSERT_TRUE( + extensions::ExtensionRegistry::Get(&profile_)->AddEnabled(extension)); + + std::string error; + ASSERT_TRUE(InvokePrinterAdded("123", "456", &error)) << error; + + ASSERT_EQ(1u, notification_ui_manager_.GetNotificationCount()); + const Notification& notification = + notification_ui_manager_.GetNotificationAt(0); + EXPECT_EQ("123:456", notification.tag()); + EXPECT_EQ( + base::StringPrintf(kPrinterAppNotFoundDelegateIDTemplate, "123", "456"), + notification.delegate_id()); +} + +TEST_F(PrinterServiceProviderAppSearchEnabledTest, VendorIdOutOfBounds) { + AddTestUser(); + + std::string error; + ASSERT_TRUE(InvokePrinterAdded("1F123", "456", &error)) << error; + + EXPECT_EQ(0u, notification_ui_manager_.GetNotificationCount()); +} + +TEST_F(PrinterServiceProviderAppSearchEnabledTest, ProductIdNaN) { + AddTestUser(); + + std::string error; + ASSERT_TRUE(InvokePrinterAdded("123", "xxx", &error)) << error; + + EXPECT_EQ(0u, notification_ui_manager_.GetNotificationCount()); +} + +TEST_F(PrinterServiceProviderAppSearchEnabledTest, VendorIdNaN) { + AddTestUser(); + + std::string error; + ASSERT_TRUE(InvokePrinterAdded("xxxfoo", "456", &error)) << error; + + EXPECT_EQ(0u, notification_ui_manager_.GetNotificationCount()); +} + +TEST_F(PrinterServiceProviderAppSearchEnabledTest, ProductIdOutOfBounds) { + AddTestUser(); + + std::string error; + ASSERT_TRUE(InvokePrinterAdded("123", "1F456", &error)) << error; + + EXPECT_EQ(0u, notification_ui_manager_.GetNotificationCount()); +} + +TEST_F(PrinterServiceProviderAppSearchEnabledTest, NegativeProductId) { + AddTestUser(); + + std::string error; + ASSERT_TRUE(InvokePrinterAdded("123", "-1", &error)) << error; + + EXPECT_EQ(0u, notification_ui_manager_.GetNotificationCount()); +} + +TEST_F(PrinterServiceProviderAppSearchEnabledTest, PrintersAddedWithNoIdArgs) { + AddTestUser(); + + test_helper_.SetUp(kPrinterAdded, &service_provider_); + dbus::MethodCall method_call(kLibCrosServiceInterface, kPrinterAdded); + dbus::MessageWriter writer(&method_call); + + // Call the PrinterAdded method. + scoped_ptr<dbus::Response> response(test_helper_.CallMethod(&method_call)); + + // An empty response should be returned. + ASSERT_TRUE(response.get()); + dbus::MessageReader reader(response.get()); + ASSERT_FALSE(reader.HasMoreData()); + test_helper_.TearDown(); + + EXPECT_EQ(0u, notification_ui_manager_.GetNotificationCount()); +} + } // namespace chromeos diff --git a/chrome/browser/chromeos/profiles/profile_helper.h b/chrome/browser/chromeos/profiles/profile_helper.h index 4223666..18a0239 100644 --- a/chrome/browser/chromeos/profiles/profile_helper.h +++ b/chrome/browser/chromeos/profiles/profile_helper.h @@ -134,6 +134,7 @@ class ProfileHelper friend class KioskTest; friend class MockUserManager; friend class MultiProfileUserControllerTest; + friend class PrinterServiceProviderAppSearchEnabledTest; friend class ProfileHelperTest; friend class ProfileListChromeOSTest; friend class SessionStateDelegateChromeOSTest; diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc index a705ae7..7b16766 100644 --- a/chromeos/chromeos_switches.cc +++ b/chromeos/chromeos_switches.cc @@ -336,6 +336,12 @@ const char kDisableWebviewSigninFlow[] = "disable-webview-signin-flow"; // Enable Chrome OS firewall hole-punching for Chrome Apps. const char kEnableFirewallHolePunching[] = "enable-firewall-hole-punching"; +// Enables searching for an app that supports a plugged in USB printer. When a +// user plugs in USB printer, they are shown a notification offering to search +// Chroem Web Store for an app that has printerProvider permission and can +// handle the plugged in printer. +const char kEnablePrinterAppSearch[] = "enable-printer-app-search"; + bool WakeOnWifiEnabled() { return !base::CommandLine::ForCurrentProcess()->HasSwitch(kDisableWakeOnWifi); } diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h index 4adab58..4c03f1d 100644 --- a/chromeos/chromeos_switches.h +++ b/chromeos/chromeos_switches.h @@ -66,6 +66,7 @@ CHROMEOS_EXPORT extern const char kEnableKioskMode[]; CHROMEOS_EXPORT extern const char kEnableNetworkPortalNotification[]; CHROMEOS_EXPORT extern const char kEnableNewKoreanIme[]; CHROMEOS_EXPORT extern const char kEnablePhysicalKeyboardAutocorrect[]; +CHROMEOS_EXPORT extern const char kEnablePrinterAppSearch[]; CHROMEOS_EXPORT extern const char kEnableRequestTabletSite[]; CHROMEOS_EXPORT extern const char kEnableScreenshotTestingWithMode[]; CHROMEOS_EXPORT extern const char kEnableTouchpadThreeFingerClick[]; |