diff options
32 files changed, 1151 insertions, 2 deletions
diff --git a/chrome/browser/extensions/api/document_scan/document_scan_api.cc b/chrome/browser/extensions/api/document_scan/document_scan_api.cc new file mode 100644 index 0000000..1af7c99 --- /dev/null +++ b/chrome/browser/extensions/api/document_scan/document_scan_api.cc @@ -0,0 +1,119 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/document_scan/document_scan_api.h" + +#include <algorithm> + +#include "content/public/browser/browser_thread.h" +#include "extensions/browser/extension_system.h" + +using content::BrowserThread; + +namespace { + +const char kScannerNotAvailable[] = "Scanner not available"; +const char kUserGestureRequiredError[] = + "User gesture required to perform scan"; +} // namespace + +namespace extensions { + +namespace api { + +DocumentScanScanFunction::DocumentScanScanFunction() + : document_scan_interface_(DocumentScanInterface::CreateInstance()) {} + +DocumentScanScanFunction::~DocumentScanScanFunction() {} + +bool DocumentScanScanFunction::Prepare() { + set_work_thread_id(BrowserThread::FILE); + params_ = document_scan::Scan::Params::Create(*args_); + EXTENSION_FUNCTION_VALIDATE(params_.get()); + return true; +} + +void DocumentScanScanFunction::AsyncWorkStart() { + if (!user_gesture()) { + error_ = kUserGestureRequiredError; + AsyncWorkCompleted(); + return; + } + + // Add a reference, which is balanced in OnScannerListReceived to keep the + // object around and allow the callback to be invoked. + AddRef(); + + document_scan_interface_->ListScanners( + base::Bind(&DocumentScanScanFunction::OnScannerListReceived, + base::Unretained(this))); +} + +void DocumentScanScanFunction::OnScannerListReceived( + const std::vector<DocumentScanInterface::ScannerDescription>& + scanner_descriptions, + const std::string& error) { + std::vector<DocumentScanInterface::ScannerDescription>::const_iterator + scanner_i = scanner_descriptions.begin(); + if (params_->options.mime_types) { + std::vector<std::string>& mime_types = *params_->options.mime_types.get(); + for (; scanner_i != scanner_descriptions.end(); ++scanner_i) { + if (std::find(mime_types.begin(), mime_types.end(), + scanner_i->image_mime_type) != mime_types.end()) { + break; + } + } + } + + if (scanner_i == scanner_descriptions.end()) { + error_ = kScannerNotAvailable; + AsyncWorkCompleted(); + + // Balance the AddRef in AsyncWorkStart(). + Release(); + return; + } + + // TODO(pstew): Display a user interface for choosing a scanner. + // This is where the scan mode, DPI, etc, would be specified. + + document_scan_interface_->Scan( + scanner_i->name, + DocumentScanInterface::kScanModeColor, + 0, + base::Bind(&DocumentScanScanFunction::OnResultsReceived, + base::Unretained(this))); +} + +void DocumentScanScanFunction::OnResultsReceived( + const std::string& scanned_image, + const std::string& mime_type, + const std::string& error) { + // TODO(pstew): Display received scan in the UI and confirm that this + // scan should be sent to the caller. If this is a multi-page scan, + // provide a means for adding additional scanned images up to the + // requested limit. + + if (error.empty()) { + document_scan::ScanResults scan_results; + if (!scanned_image.empty()) { + scan_results.data_urls.push_back(scanned_image); + } + scan_results.mime_type = mime_type; + results_ = document_scan::Scan::Results::Create(scan_results); + } + error_ = error; + AsyncWorkCompleted(); + + // Balance the AddRef in AsyncWorkStart(). + Release(); +} + +bool DocumentScanScanFunction::Respond() { + return error_.empty(); +} + +} // namespace api + +} // namespace extensions diff --git a/chrome/browser/extensions/api/document_scan/document_scan_api.h b/chrome/browser/extensions/api/document_scan/document_scan_api.h new file mode 100644 index 0000000..30686b7 --- /dev/null +++ b/chrome/browser/extensions/api/document_scan/document_scan_api.h @@ -0,0 +1,55 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <string> +#include <vector> + +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/extensions/api/document_scan/document_scan_interface.h" +#include "chrome/common/extensions/api/document_scan.h" +#include "extensions/browser/api/async_api_function.h" + +#ifndef CHROME_BROWSER_EXTENSIONS_API_DOCUMENT_SCAN_DOCUMENT_SCAN_FUNCTION_H_ +#define CHROME_BROWSER_EXTENSIONS_API_DOCUMENT_SCAN_DOCUMENT_SCAN_FUNCTION_H_ + +namespace extensions { + +namespace api { + +class DocumentScanScanFunction : public AsyncApiFunction { + public: + DECLARE_EXTENSION_FUNCTION("documentScan.scan", + DOCUMENT_SCAN_SCAN) + DocumentScanScanFunction(); + + protected: + ~DocumentScanScanFunction(); + + // AsyncApiFunction: + virtual bool Prepare() override; + virtual void AsyncWorkStart() override; + virtual bool Respond() override; + + private: + friend class DocumentScanScanFunctionTest; + + void OnScannerListReceived( + const std::vector<DocumentScanInterface::ScannerDescription>& + scanner_descriptions, + const std::string& error); + void OnResultsReceived(const std::string& scanned_image, + const std::string& mime_type, + const std::string& error); + + scoped_ptr<document_scan::Scan::Params> params_; + scoped_ptr<DocumentScanInterface> document_scan_interface_; + + DISALLOW_COPY_AND_ASSIGN(DocumentScanScanFunction); +}; + +} // namespace api + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_API_DOCUMENT_SCAN_DOCUMENT_SCAN_FUNCTION_H_ diff --git a/chrome/browser/extensions/api/document_scan/document_scan_api_unittest.cc b/chrome/browser/extensions/api/document_scan/document_scan_api_unittest.cc new file mode 100644 index 0000000..40faad2 --- /dev/null +++ b/chrome/browser/extensions/api/document_scan/document_scan_api_unittest.cc @@ -0,0 +1,123 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "chrome/browser/extensions/api/document_scan/document_scan_api.h" + +#include <string> +#include <vector> + +#include "chrome/browser/extensions/api/document_scan/mock_document_scan_interface.h" +#include "chrome/browser/extensions/extension_api_unittest.h" +#include "chrome/browser/extensions/extension_function_test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; + +namespace extensions { + +namespace api { + +// Tests of networking_private_crypto support for Networking Private API. +class DocumentScanScanFunctionTest : public ExtensionApiUnittest { + public: + DocumentScanScanFunctionTest() + : function_(new DocumentScanScanFunction()), + document_scan_interface_(new MockDocumentScanInterface()) {} + virtual ~DocumentScanScanFunctionTest() {} + + void SetUp() { + ExtensionApiUnittest::SetUp(); + // Passes ownership. + function_->document_scan_interface_.reset(document_scan_interface_); + } + + protected: + std::string RunFunctionAndReturnError(const std::string& args) { + function_->set_extension(extension()); + std::string error = + extension_function_test_utils::RunFunctionAndReturnError( + function_, args, browser(), + extension_function_test_utils::NONE); + return error; + } + + DocumentScanScanFunction* function_; + MockDocumentScanInterface* document_scan_interface_; // Owned by function_. +}; + +ACTION_P2(InvokeListScannersCallback, scanner_list, error) { + ::std::tr1::get<0>(args).Run(scanner_list, error); +} + +ACTION_P3(InvokeScanCallback, data, mime_type, error) { + ::std::tr1::get<3>(args).Run(data, mime_type, error); +} + +TEST_F(DocumentScanScanFunctionTest, GestureRequired) { + EXPECT_EQ("User gesture required to perform scan", + RunFunctionAndReturnError("[{}]")); +} + +TEST_F(DocumentScanScanFunctionTest, NoScanners) { + function_->set_user_gesture(true); + EXPECT_CALL(*document_scan_interface_, ListScanners(_)) + .WillOnce(InvokeListScannersCallback( + std::vector<DocumentScanInterface::ScannerDescription>(), + "")); + EXPECT_EQ("Scanner not available", + RunFunctionAndReturnError("[{}]")); +} + +TEST_F(DocumentScanScanFunctionTest, NoMatchingScanners) { + function_->set_user_gesture(true); + std::vector<DocumentScanInterface::ScannerDescription> scanner_list; + DocumentScanInterface::ScannerDescription scanner; + scanner.image_mime_type = "img/fresco"; + scanner_list.push_back(scanner); + EXPECT_CALL(*document_scan_interface_, ListScanners(_)) + .WillOnce(InvokeListScannersCallback(scanner_list, "")); + EXPECT_EQ( + "Scanner not available", + RunFunctionAndReturnError("[{\"mimeTypes\": [\"img/silverpoint\"]}]")); +} + +TEST_F(DocumentScanScanFunctionTest, ScanFailure) { + function_->set_user_gesture(true); + std::vector<DocumentScanInterface::ScannerDescription> scanner_list; + DocumentScanInterface::ScannerDescription scanner; + const char kMimeType[] = "img/tempera"; + const char kScannerName[] = "Michelangelo"; + scanner.name = kScannerName; + scanner.image_mime_type = kMimeType; + scanner_list.push_back(scanner); + EXPECT_CALL(*document_scan_interface_, ListScanners(_)) + .WillOnce(InvokeListScannersCallback(scanner_list, "")); + const char kScanError[] = "Someone ate all the eggs"; + EXPECT_CALL(*document_scan_interface_, Scan(kScannerName, _, _, _)) + .WillOnce(InvokeScanCallback("", "", kScanError)); + EXPECT_EQ(kScanError, + RunFunctionAndReturnError("[{\"mimeTypes\": [\"img/tempera\"]}]")); +} + +TEST_F(DocumentScanScanFunctionTest, Success) { + std::vector<DocumentScanInterface::ScannerDescription> scanner_list; + scanner_list.push_back(DocumentScanInterface::ScannerDescription()); + EXPECT_CALL(*document_scan_interface_, ListScanners(_)) + .WillOnce(InvokeListScannersCallback(scanner_list, "")); + const char kScanData[] = "A beautiful picture"; + const char kMimeType[] = "img/encaustic"; + EXPECT_CALL(*document_scan_interface_, Scan(_, _, _, _)) + .WillOnce(InvokeScanCallback(kScanData, kMimeType, "")); + function_->set_user_gesture(true); + scoped_ptr<base::DictionaryValue> result(RunFunctionAndReturnDictionary( + function_, "[{}]")); + ASSERT_NE(nullptr, result.get()); + document_scan::ScanResults scan_results; + EXPECT_TRUE(document_scan::ScanResults::Populate(*result, &scan_results)); + EXPECT_THAT(scan_results.data_urls, testing::ElementsAre(kScanData)); + EXPECT_EQ(kMimeType, scan_results.mime_type); +} + +} // namespace api + +} // namespace extensions diff --git a/chrome/browser/extensions/api/document_scan/document_scan_interface.cc b/chrome/browser/extensions/api/document_scan/document_scan_interface.cc new file mode 100644 index 0000000..be0149d --- /dev/null +++ b/chrome/browser/extensions/api/document_scan/document_scan_interface.cc @@ -0,0 +1,26 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "document_scan_interface.h" + +namespace extensions { + +namespace api { + +DocumentScanInterface::DocumentScanInterface() { +} + +DocumentScanInterface::~DocumentScanInterface() { +} + +DocumentScanInterface::ScannerDescription::ScannerDescription() { +} + +DocumentScanInterface::ScannerDescription::~ScannerDescription() { +} + +} // namespace api + +} // namespace extensions + diff --git a/chrome/browser/extensions/api/document_scan/document_scan_interface.h b/chrome/browser/extensions/api/document_scan/document_scan_interface.h new file mode 100644 index 0000000..675e097 --- /dev/null +++ b/chrome/browser/extensions/api/document_scan/document_scan_interface.h @@ -0,0 +1,64 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <string> +#include <vector> + +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" + +#ifndef CHROME_BROWSER_EXTENSIONS_API_DOCUMENT_SCAN_DOCUMENT_SCAN_INTERFACE_H_ +#define CHROME_BROWSER_EXTENSIONS_API_DOCUMENT_SCAN_DOCUMENT_SCAN_INTERFACE_H_ + +namespace extensions { + +namespace api { + +class DocumentScanInterface { + public: + struct ScannerDescription { + ScannerDescription(); + ~ScannerDescription(); + std::string name; + std::string manufacturer; + std::string model; + std::string scanner_type; + std::string image_mime_type; + }; + + enum ScanMode { + kScanModeColor, + kScanModeGray, + kScanModeLineart + }; + + typedef base::Callback<void( + const std::vector<ScannerDescription>& scanner_descriptions, + const std::string& error)> ListScannersResultsCallback; + + typedef base::Callback<void( + const std::string& scanned_image, + const std::string& mime_type, + const std::string& error)> ScanResultsCallback; + + virtual ~DocumentScanInterface(); + + virtual void Scan(const std::string& scanner_name, + ScanMode mode, + int resolution_dpi, + const ScanResultsCallback& callback) = 0; + virtual void ListScanners(const ListScannersResultsCallback& callback) = 0; + + // Creates a platform-specific DocumentScanInterface instance. + static DocumentScanInterface *CreateInstance(); + + protected: + DocumentScanInterface(); +}; + +} // namespace api + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_API_DOCUMENT_SCAN_DOCUMENT_SCAN_INTERFACE_H_ diff --git a/chrome/browser/extensions/api/document_scan/document_scan_interface_chromeos.cc b/chrome/browser/extensions/api/document_scan/document_scan_interface_chromeos.cc new file mode 100644 index 0000000..c91cb0b --- /dev/null +++ b/chrome/browser/extensions/api/document_scan/document_scan_interface_chromeos.cc @@ -0,0 +1,161 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/document_scan/document_scan_interface_chromeos.h" + +#include "base/base64.h" +#include "base/task_runner_util.h" +#include "base/threading/worker_pool.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/lorgnette_manager_client.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +namespace { + +const char kImageScanFailedError[] = "Image scan failed"; +const char kScannerImageMimeTypePng[] = "image/png"; +const char kPngImageDataUrlPrefix[] = "data:image/png;base64,"; + +} // namespace + +namespace extensions { + +namespace api { + +DocumentScanInterfaceChromeos::DocumentScanInterfaceChromeos() + : lorgnette_manager_client_(nullptr) {} + +DocumentScanInterfaceChromeos::~DocumentScanInterfaceChromeos() {} + +void DocumentScanInterfaceChromeos::ListScanners( + const ListScannersResultsCallback& callback) { + GetLorgnetteManagerClient()->ListScanners(base::Bind( + &DocumentScanInterfaceChromeos::OnScannerListReceived, + base::Unretained(this), + callback)); +} + +void DocumentScanInterfaceChromeos::OnScannerListReceived( + const ListScannersResultsCallback& callback, + bool succeeded, + const chromeos::LorgnetteManagerClient::ScannerTable &scanners) { + std::vector<ScannerDescription> scanner_descriptions; + for (chromeos::LorgnetteManagerClient::ScannerTable::const_iterator iter = + scanners.begin(); + iter != scanners.end(); + ++iter) { + ScannerDescription description; + description.name = iter->first; + const chromeos::LorgnetteManagerClient::ScannerTableEntry &entry = + iter->second; + chromeos::LorgnetteManagerClient::ScannerTableEntry::const_iterator info_it; + info_it = entry.find(lorgnette::kScannerPropertyManufacturer); + if (info_it != entry.end()) { + description.manufacturer = info_it->second; + } + info_it = entry.find(lorgnette::kScannerPropertyModel); + if (info_it != entry.end()) { + description.model = info_it->second; + } + info_it = entry.find(lorgnette::kScannerPropertyType); + if (info_it != entry.end()) { + description.scanner_type = info_it->second; + } + description.image_mime_type = kScannerImageMimeTypePng; + scanner_descriptions.push_back(description); + } + callback.Run(scanner_descriptions, ""); +} + +void DocumentScanInterfaceChromeos::Scan(const std::string& scanner_name, + ScanMode mode, + int resolution_dpi, + const ScanResultsCallback& callback) { + VLOG(1) << "Choosing scanner " << scanner_name; + chromeos::LorgnetteManagerClient::ScanProperties properties; + switch (mode) { + case kScanModeColor: + properties.mode = lorgnette::kScanPropertyModeColor; + break; + + case kScanModeGray: + properties.mode = lorgnette::kScanPropertyModeGray; + break; + + case kScanModeLineart: + properties.mode = lorgnette::kScanPropertyModeLineart; + break; + + default: + // Leave the mode parameter empty, thereby using the default. + break; + } + + if (resolution_dpi != 0) { + properties.resolution_dpi = resolution_dpi; + } + + const bool kTasksAreSlow = true; + scoped_refptr<base::TaskRunner> task_runner = + base::WorkerPool::GetTaskRunner(kTasksAreSlow); + + pipe_reader_.reset(new chromeos::PipeReaderForString( + task_runner, + base::Bind(&DocumentScanInterfaceChromeos::OnScanDataCompleted, + base::Unretained(this)))); + base::File file = pipe_reader_->StartIO(); + base::PlatformFile platform_file = file.TakePlatformFile(); + VLOG(1) << "ScanImage platform_file is " << platform_file; + GetLorgnetteManagerClient()->ScanImage( + scanner_name, platform_file, properties, + base::Bind(&DocumentScanInterfaceChromeos::OnScanCompleted, + base::Unretained(this), + callback)); +} + +void DocumentScanInterfaceChromeos::OnScanCompleted( + const ScanResultsCallback &callback, bool succeeded) { + VLOG(1) << "ScanImage returns " << succeeded; + if (pipe_reader_.get()) { + pipe_reader_->OnDataReady(-1); // terminate data stream + } + + std::string error_string; + if (!succeeded) { + error_string = kImageScanFailedError; + } + + callback.Run(GetImageURL(scanned_image_data_), kScannerImageMimeTypePng, + error_string); +} + +std::string DocumentScanInterfaceChromeos::GetImageURL(std::string image_data) { + std::string image_data_base64; + base::Base64Encode(image_data, &image_data_base64); + return std::string(kPngImageDataUrlPrefix) + image_data_base64; +} + +void DocumentScanInterfaceChromeos::OnScanDataCompleted() { + pipe_reader_->GetData(&scanned_image_data_); + pipe_reader_.reset(); +} + +chromeos::LorgnetteManagerClient* + DocumentScanInterfaceChromeos::GetLorgnetteManagerClient() { + if (!lorgnette_manager_client_) { + lorgnette_manager_client_ = + chromeos::DBusThreadManager::Get()->GetLorgnetteManagerClient(); + CHECK(lorgnette_manager_client_); + } + return lorgnette_manager_client_; +} + +// static +DocumentScanInterface *DocumentScanInterface::CreateInstance() { + return new DocumentScanInterfaceChromeos(); +} + +} // namespace api + +} // namespace extensions diff --git a/chrome/browser/extensions/api/document_scan/document_scan_interface_chromeos.h b/chrome/browser/extensions/api/document_scan/document_scan_interface_chromeos.h new file mode 100644 index 0000000..d54bbd1 --- /dev/null +++ b/chrome/browser/extensions/api/document_scan/document_scan_interface_chromeos.h @@ -0,0 +1,51 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_API_DOCUMENT_SCAN_DOCUMENT_SCAN_INTERFACE_CHROMEOS_H_ +#define CHROME_BROWSER_EXTENSIONS_API_DOCUMENT_SCAN_DOCUMENT_SCAN_INTERFACE_CHROMEOS_H_ + +#include "chrome/browser/extensions/api/document_scan/document_scan_interface.h" +#include "chromeos/dbus/lorgnette_manager_client.h" +#include "chromeos/dbus/pipe_reader.h" + +namespace extensions { + +namespace api { + +class DocumentScanInterfaceChromeos : public DocumentScanInterface { + public: + DocumentScanInterfaceChromeos(); + virtual ~DocumentScanInterfaceChromeos(); + + virtual void ListScanners( + const ListScannersResultsCallback& callback) override; + virtual void Scan(const std::string& scanner_name, + ScanMode mode, + int resolution_dpi, + const ScanResultsCallback& callback) override; + + private: + friend class DocumentScanInterfaceChromeosTest; + + void OnScannerListReceived( + const ListScannersResultsCallback& callback, + bool succeeded, + const chromeos::LorgnetteManagerClient::ScannerTable &scanners); + void OnScanCompleted(const ScanResultsCallback &callback, bool succeeded); + void OnScanDataCompleted(); + std::string GetImageURL(std::string image_data); + chromeos::LorgnetteManagerClient* GetLorgnetteManagerClient(); + + scoped_ptr<chromeos::PipeReaderForString> pipe_reader_; + std::string scanned_image_data_; + chromeos::LorgnetteManagerClient* lorgnette_manager_client_; + + DISALLOW_COPY_AND_ASSIGN(DocumentScanInterfaceChromeos); +}; + +} // namespace api + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_API_DOCUMENT_SCAN_DOCUMENT_SCAN_INTERFACE_CHROMEOS_H_ diff --git a/chrome/browser/extensions/api/document_scan/document_scan_interface_chromeos_unittest.cc b/chrome/browser/extensions/api/document_scan/document_scan_interface_chromeos_unittest.cc new file mode 100644 index 0000000..a84fe0b --- /dev/null +++ b/chrome/browser/extensions/api/document_scan/document_scan_interface_chromeos_unittest.cc @@ -0,0 +1,168 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "chrome/browser/extensions/api/document_scan/document_scan_interface_chromeos.h" + +#include <string> +#include <vector> + +#include "base/bind.h" +#include "base/test/test_simple_task_runner.h" +#include "base/thread_task_runner_handle.h" +#include "chromeos/dbus/mock_lorgnette_manager_client.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +using testing::_; + +namespace extensions { + +namespace api { + +// Tests of networking_private_crypto support for Networking Private API. +class DocumentScanInterfaceChromeosTest : public testing::Test { + public: + DocumentScanInterfaceChromeosTest() + : client_(new chromeos::MockLorgnetteManagerClient()) {} + virtual ~DocumentScanInterfaceChromeosTest() {} + + void SetUp() { + // This is needed to create a valid PipeReader object. + task_runner_ = new base::TestSimpleTaskRunner(); + thread_task_runner_handle_.reset( + new base::ThreadTaskRunnerHandle(task_runner_)); + scan_interface_.lorgnette_manager_client_ = client_.get(); + } + + virtual void TearDown() override { + thread_task_runner_handle_.reset(); + task_runner_ = NULL; + } + + MOCK_METHOD2( + OnListScannersResultReceived, + void(const std::vector<DocumentScanInterface::ScannerDescription>& + scanners, + const std::string& error)); + + MOCK_METHOD3(OnScanCompleted, void(const std::string& scanned_image, + const std::string& mime_type, + const std::string& error)); + + chromeos::PipeReader *GetPipeReader() { + return scan_interface_.pipe_reader_.get(); + } + + protected: + DocumentScanInterfaceChromeos scan_interface_; + scoped_ptr<chromeos::MockLorgnetteManagerClient> client_; + scoped_refptr<base::TestSimpleTaskRunner> task_runner_; + scoped_ptr<base::ThreadTaskRunnerHandle> thread_task_runner_handle_; +}; + +ACTION_P2(InvokeListScannersCallback, scanner_list, error) { + ::std::tr1::get<0>(args).Run(scanner_list, error); +} + +ACTION_P2(InvokePipeReader, test, data) { + test->GetPipeReader()->AcceptData(data.c_str(), data.size()); +} + +ACTION_P(InvokeScanCallback, succeeded) { + ::std::tr1::get<3>(args).Run(succeeded); +} + +MATCHER_P5(IsScannerDescription, name, manufacturer, model, type, mime, "") { + return + arg.name == name && + arg.manufacturer == manufacturer && + arg.model == model && + arg.scanner_type == type && + arg.image_mime_type == mime; +} + +MATCHER_P2(IsScannerProperties, mode, resolution, "") { + return arg.mode == mode && arg.resolution_dpi == resolution; +} + +TEST_F(DocumentScanInterfaceChromeosTest, ListScanners) { + chromeos::LorgnetteManagerClient::ScannerTable scanners; + const char kScannerName[] = "Monet"; + chromeos::LorgnetteManagerClient::ScannerTableEntry entry; + const char kScannerManufacturer[] = "Jacques-Louis David"; + entry[lorgnette::kScannerPropertyManufacturer] = kScannerManufacturer; + const char kScannerModel[] = "Le Havre"; + entry[lorgnette::kScannerPropertyModel] = kScannerModel; + const char kScannerType[] = "Impressionism"; + entry[lorgnette::kScannerPropertyType] = kScannerType; + scanners[kScannerName] = entry; + EXPECT_CALL(*client_, ListScanners(_)) + .WillOnce(InvokeListScannersCallback(true, scanners)); + EXPECT_CALL(*this, OnListScannersResultReceived( + testing::ElementsAre( + IsScannerDescription(kScannerName, + kScannerManufacturer, + kScannerModel, + kScannerType, + "image/png")), "")); + scan_interface_.ListScanners(base::Bind( + &DocumentScanInterfaceChromeosTest::OnListScannersResultReceived, + base::Unretained(this))); +} + +TEST_F(DocumentScanInterfaceChromeosTest, ScanFailure) { + const char kScannerName[] = "Monet"; + const int kResolution = 4096; + EXPECT_TRUE(base::ThreadTaskRunnerHandle::IsSet()); + EXPECT_CALL(*client_, ScanImage( + kScannerName, + _, + IsScannerProperties( + lorgnette::kScanPropertyModeColor, + kResolution), + _)).WillOnce(InvokeScanCallback(false)); + EXPECT_CALL(*this, OnScanCompleted("data:image/png;base64,", + "image/png", + "Image scan failed")); + scan_interface_.Scan( + kScannerName, + DocumentScanInterface::kScanModeColor, + kResolution, + base::Bind( + &DocumentScanInterfaceChromeosTest::OnScanCompleted, + base::Unretained(this))); +} + +TEST_F(DocumentScanInterfaceChromeosTest, ScanSuccess) { + const char kScannerName[] = "Monet"; + const int kResolution = 4096; + EXPECT_TRUE(base::ThreadTaskRunnerHandle::IsSet()); + EXPECT_CALL(*client_, + ScanImage( + kScannerName, + _, + IsScannerProperties( + lorgnette::kScanPropertyModeColor, + kResolution), + _)) + .WillOnce(testing::DoAll( + InvokePipeReader(this, std::string("PrettyPicture")), + InvokeScanCallback(true))); + + // Data URL plus base64 representation of "PrettyPicture". + const char kExpectedImageData[] = + "data:image/png;base64,UHJldHR5UGljdHVyZQ=="; + + EXPECT_CALL(*this, OnScanCompleted(kExpectedImageData, "image/png", "")); + scan_interface_.Scan( + kScannerName, + DocumentScanInterface::kScanModeColor, + kResolution, + base::Bind( + &DocumentScanInterfaceChromeosTest::OnScanCompleted, + base::Unretained(this))); +} + +} // namespace api + +} // namespace extensions diff --git a/chrome/browser/extensions/api/document_scan/document_scan_interface_nonchromeos.cc b/chrome/browser/extensions/api/document_scan/document_scan_interface_nonchromeos.cc new file mode 100644 index 0000000..cd21037 --- /dev/null +++ b/chrome/browser/extensions/api/document_scan/document_scan_interface_nonchromeos.cc @@ -0,0 +1,44 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/document_scan/document_scan_interface.h" + +namespace { + +const char kScanFunctionNotImplementedError[] = "Scan function not implemented"; + +} // namespace + +namespace extensions { + +namespace api { + +class DocumentScanInterfaceImpl : public DocumentScanInterface { + public: + DocumentScanInterfaceImpl() {} + virtual ~DocumentScanInterfaceImpl() {} + + virtual void ListScanners( + const ListScannersResultsCallback& callback) override { + callback.Run(std::vector<ScannerDescription> (), ""); + } + virtual void Scan(const std::string& scanner_name, + ScanMode mode, + int resolution_dpi, + const ScanResultsCallback& callback) override { + callback.Run("", "", kScanFunctionNotImplementedError); + } + + private: + DISALLOW_COPY_AND_ASSIGN(DocumentScanInterfaceImpl); +}; + +// static +DocumentScanInterface *DocumentScanInterface::CreateInstance() { + return new DocumentScanInterfaceImpl(); +} + +} // namespace api + +} // namespace extensions diff --git a/chrome/browser/extensions/api/document_scan/mock_document_scan_interface.cc b/chrome/browser/extensions/api/document_scan/mock_document_scan_interface.cc new file mode 100644 index 0000000..830575f --- /dev/null +++ b/chrome/browser/extensions/api/document_scan/mock_document_scan_interface.cc @@ -0,0 +1,20 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mock_document_scan_interface.h" + +namespace extensions { + +namespace api { + +MockDocumentScanInterface::MockDocumentScanInterface() { +} + +MockDocumentScanInterface::~MockDocumentScanInterface() { +} + +} // namespace api + +} // namespace extensions + diff --git a/chrome/browser/extensions/api/document_scan/mock_document_scan_interface.h b/chrome/browser/extensions/api/document_scan/mock_document_scan_interface.h new file mode 100644 index 0000000..8303147 --- /dev/null +++ b/chrome/browser/extensions/api/document_scan/mock_document_scan_interface.h @@ -0,0 +1,35 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_API_DOCUMENT_SCAN_MOCK_DOCUMENT_SCAN_INTERFACE_H_ +#define CHROME_BROWSER_EXTENSIONS_API_DOCUMENT_SCAN_MOCK_DOCUMENT_SCAN_INTERFACE_H_ + +#include <string> + +#include <gmock/gmock.h> + +#include "chrome/browser/extensions/api/document_scan/document_scan_interface.h" + +namespace extensions { + +namespace api { + +class MockDocumentScanInterface : public DocumentScanInterface { + public: + MockDocumentScanInterface(); + virtual ~MockDocumentScanInterface(); + + MOCK_METHOD4(Scan, void(const std::string& scanner_name, + ScanMode mode, + int resolution_dpi, + const ScanResultsCallback& callback)); + MOCK_METHOD1(ListScanners, void(const ListScannersResultsCallback& callback)); + MOCK_CONST_METHOD0(GetImageMimeType, std::string()); +}; + +} // namespace api + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_API_DOCUMENT_SCAN_MOCK_DOCUMENT_SCAN_INTERFACE_H_ diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index 68ef123..68d75b3 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -8,6 +8,7 @@ 'browser/extensions/api/diagnostics/diagnostics_api.cc', 'browser/extensions/api/diagnostics/diagnostics_api.h', 'browser/extensions/api/diagnostics/diagnostics_api_chromeos.cc', + 'browser/extensions/api/document_scan/document_scan_interface_chromeos.cc', 'browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc', 'browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.h', 'browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc', @@ -37,6 +38,7 @@ 'browser/extensions/updater/local_extension_cache.h', ], 'chrome_browser_extensions_non_chromeos_sources': [ + 'browser/extensions/api/document_scan/document_scan_interface_nonchromeos.cc', 'browser/extensions/api/easy_unlock_private/easy_unlock_private_crypto_delegate_stub.cc', 'browser/extensions/api/feedback_private/feedback_service_nonchromeos.cc', 'browser/extensions/api/image_writer_private/operation_nonchromeos.cc', @@ -208,6 +210,10 @@ 'browser/extensions/api/dial/dial_registry.h', 'browser/extensions/api/dial/dial_service.cc', 'browser/extensions/api/dial/dial_service.h', + 'browser/extensions/api/document_scan/document_scan_interface.cc', + 'browser/extensions/api/document_scan/document_scan_interface.h', + 'browser/extensions/api/document_scan/document_scan_api.cc', + 'browser/extensions/api/document_scan/document_scan_api.h', 'browser/extensions/api/downloads/downloads_api.cc', 'browser/extensions/api/downloads/downloads_api.h', 'browser/extensions/api/downloads_internal/downloads_internal_api.cc', diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 7098c86..53f02db 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -322,6 +322,8 @@ 'browser/extensions/api/dial/dial_device_data_unittest.cc', 'browser/extensions/api/dial/dial_registry_unittest.cc', 'browser/extensions/api/dial/dial_service_unittest.cc', + 'browser/extensions/api/document_scan/document_scan_api_unittest.cc', + 'browser/extensions/api/document_scan/mock_document_scan_interface.cc', 'browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc', 'browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc', 'browser/extensions/api/experience_sampling_private/experience_sampling_private_api_unittest.cc', @@ -2308,6 +2310,7 @@ 'browser/upgrade_detector_impl_unittest.cc', ], 'sources': [ + 'browser/extensions/api/document_scan/document_scan_interface_chromeos_unittest.cc', 'browser/extensions/updater/local_extension_cache_unittest.cc', 'browser/metrics/chromeos_metrics_provider_unittest.cc', ], diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json index 1f61fef..560d308 100644 --- a/chrome/common/extensions/api/_api_features.json +++ b/chrome/common/extensions/api/_api_features.json @@ -250,6 +250,11 @@ "dependencies": ["permission:dial"], "contexts": ["blessed_extension"] }, + "documentScan": { + "platforms": ["chromeos"], + "dependencies": ["permission:documentScan"], + "contexts": ["blessed_extension"] + }, "downloads": { "dependencies": ["permission:downloads"], "contexts": ["blessed_extension"] diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json index 8e109cf..88ec512 100644 --- a/chrome/common/extensions/api/_permission_features.json +++ b/chrome/common/extensions/api/_permission_features.json @@ -330,6 +330,10 @@ "channel": "stable", "extension_types": ["extension", "platform_app"] }, + "documentScan": { + "channel": "dev", + "extension_types": ["extension", "platform_app"] + }, "downloads": { "channel": "stable", "extension_types": ["extension"] diff --git a/chrome/common/extensions/api/document_scan.idl b/chrome/common/extensions/api/document_scan.idl new file mode 100644 index 0000000..0428d4a --- /dev/null +++ b/chrome/common/extensions/api/document_scan.idl @@ -0,0 +1,36 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Use the <code>chrome.document_scan</code> API to discover and retrieve +// images from attached paper document scanners. +namespace documentScan { + dictionary ScanOptions { + // The MIME types that are accepted by the caller. + DOMString[]? mimeTypes; + + // The number of scanned images allowed (defaults to 1). + long? maxImages; + }; + + dictionary ScanResults { + // The data image URLs in a form that can be passed as the "src" value to + // an image tag. + DOMString[] dataUrls; + + // The MIME type of |dataUrls|. + DOMString mimeType; + }; + + // Callback from the <code>scan</code> method; on success + // the results from the scan is returned in |results|. + callback ScanCallback = void (ScanResults results); + + interface Functions { + // Performs a document scan. On success, the PNG data will be + // sent to the callback. + // |options| : <code>Options</code> object containing scan parameters. + // |callback| : Called with the result and data from the scan. + static void scan(ScanOptions options, ScanCallback callback); + }; +}; diff --git a/chrome/common/extensions/api/schemas.gypi b/chrome/common/extensions/api/schemas.gypi index a0e2e76..680320f 100644 --- a/chrome/common/extensions/api/schemas.gypi +++ b/chrome/common/extensions/api/schemas.gypi @@ -32,6 +32,7 @@ 'desktop_capture.json', 'developer_private.idl', 'dial.idl', + 'document_scan.idl', 'downloads.idl', 'downloads_internal.idl', 'easy_unlock_private.idl', diff --git a/chrome/common/extensions/docs/examples/api/document_scan/README.md b/chrome/common/extensions/docs/examples/api/document_scan/README.md new file mode 100644 index 0000000..22c61ca --- /dev/null +++ b/chrome/common/extensions/docs/examples/api/document_scan/README.md @@ -0,0 +1,10 @@ +# Document Scanning API Sample + +This demo interfaces with the Chrome document scanning API to acquire scanned +images. + +## APIs + +* [Document scanning API](https://developer.chrome.com/apps/document_scan) +* [Runtime](https://developer.chrome.com/apps/runtime) +* [Window](https://developer.chrome.com/apps/app_window) diff --git a/chrome/common/extensions/docs/examples/api/document_scan/background.js b/chrome/common/extensions/docs/examples/api/document_scan/background.js new file mode 100644 index 0000000..7f7faf2 --- /dev/null +++ b/chrome/common/extensions/docs/examples/api/document_scan/background.js @@ -0,0 +1,14 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +chrome.app.runtime.onLaunched.addListener(function() { + chrome.app.window.create('scan.html', { + singleton: true, + id: "ChromeApps-Sample-Document-Scan", + bounds: { + 'width': 480, + 'height': 640 + } + }); +}); diff --git a/chrome/common/extensions/docs/examples/api/document_scan/manifest.json b/chrome/common/extensions/docs/examples/api/document_scan/manifest.json new file mode 100644 index 0000000..8f788d3 --- /dev/null +++ b/chrome/common/extensions/docs/examples/api/document_scan/manifest.json @@ -0,0 +1,13 @@ +{ + "name": "Document Scanning API Sample", + "version": "0.1", + "manifest_version": 2, + "minimum_chrome_version": "37", + "app": { + "background": { + "scripts": ["background.js"] + } + }, + "permissions": [], + "optional_permissions": [ "documentScan" ] +} diff --git a/chrome/common/extensions/docs/examples/api/document_scan/scan.css b/chrome/common/extensions/docs/examples/api/document_scan/scan.css new file mode 100644 index 0000000..08a4385 --- /dev/null +++ b/chrome/common/extensions/docs/examples/api/document_scan/scan.css @@ -0,0 +1,37 @@ +/* Copyright 2014 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#waitAnimation { + position: absolute; + left: 0px; + top: 0px; + height:100%; + width:100%; + z-index:1000; + background-color:black; + opacity:0.6; +} + +#waitSpinner { + position: absolute; + height:60px; + width:60px; + top: 50%; + left: 50%; + margin-left: -30px; + margin-top: -30px; + -webkit-animation: rotation .6s infinite linear; + animation: rotation .6s infinite linear; + border-left:6px solid rgba(180,174,239,.15); + border-right:6px solid rgba(180,174,239,.15); + border-bottom:6px solid rgba(180,174,239,.15); + border-top:6px solid rgba(180,174,239,.8); + border-radius:100%; +} + +@-webkit-keyframes rotation { + from {-webkit-transform: rotate(0deg);} + to {-webkit-transform: rotate(359deg);} +} diff --git a/chrome/common/extensions/docs/examples/api/document_scan/scan.html b/chrome/common/extensions/docs/examples/api/document_scan/scan.html new file mode 100644 index 0000000..a7b24b6 --- /dev/null +++ b/chrome/common/extensions/docs/examples/api/document_scan/scan.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> + <head> + <title>Scanner Control</title> + <link rel="stylesheet" type="text/css" href="scan.css"> + </head> + <body> + <div id="waitAnimation" style="display: none;"> + <div id="waitSpinner"></div> + </div> + </img> + <button id="requestButton">Request App permissions</button> + <button id="scanButton">Scan</button> + <div id="scannedImages"> + </div> + <script src="scan.js"></script> + </body> +</html> diff --git a/chrome/common/extensions/docs/examples/api/document_scan/scan.js b/chrome/common/extensions/docs/examples/api/document_scan/scan.js new file mode 100644 index 0000000..23d8495 --- /dev/null +++ b/chrome/common/extensions/docs/examples/api/document_scan/scan.js @@ -0,0 +1,69 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var requestButton = document.getElementById("requestButton"); +var scanButton = document.getElementById('scanButton'); +var scannedImages = document.getElementById('scannedImages'); +var waitAnimation = document.getElementById('waitAnimation'); +var imageMimeType; + +function setOnlyChild(parent, child) { + while (parent.firstChild) { + parent.removeChild(parent.firstChild); + } + parent.appendChild(child); +} + +var gotPermission = function(result) { + waitAnimation.style.display = 'block'; + requestButton.style.display = 'none'; + scanButton.style.display = 'block'; + console.log('App was granted the "documentScan" permission.'); + waitAnimation.style.display = 'none'; +}; + +var permissionObj = {permissions: ['documentScan']}; + +requestButton.addEventListener('click', function() { + waitAnimation.style.display = 'block'; + chrome.permissions.request( permissionObj, function(result) { + if (result) { + gotPermission(); + } else { + console.log('App was not granted the "documentScan" permission.'); + console.log(chrome.runtime.lastError); + } + }); +}); + +var onScanCompleted = function(scan_results) { + waitAnimation.style.display = 'none'; + if (chrome.runtime.lastError) { + console.log('Scan failed: ' + chrome.runtime.lastError.message); + return; + } + numImages = scan_results.dataUrls.length; + console.log('Scan completed with ' + numImages + ' images.'); + for (var i = 0; i < numImages; i++) { + urlData = scan_results.dataUrls[i] + console.log('Scan ' + i + ' data length ' + + urlData.length + '.'); + console.log('URL is ' + urlData); + var scannedImage = document.createElement('img'); + scannedImage.src = urlData; + scannedImages.insertBefore(scannedImage, scannedImages.firstChild); + } +}; + +scanButton.addEventListener('click', function() { + var scanProperties = {}; + waitAnimation.style.display = 'block'; + chrome.documentScan.scan(scanProperties, onScanCompleted); +}); + +chrome.permissions.contains(permissionObj, function(result) { + if (result) { + gotPermission(); + } +}); diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc index 9c8cc20..875d2c1 100644 --- a/chrome/common/extensions/permissions/chrome_api_permissions.cc +++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc @@ -118,6 +118,9 @@ std::vector<APIPermissionInfo*> ChromeAPIPermissions::GetAllPermissions() IDS_EXTENSION_PROMPT_WARNING_COPRESENCE, PermissionMessage::kCopresence}, {APIPermission::kCopresencePrivate, "copresencePrivate"}, + {APIPermission::kDocumentScan, "documentScan", + APIPermissionInfo::kFlagNone, IDS_EXTENSION_PROMPT_WARNING_DOCUMENT_SCAN, + PermissionMessage::kDocumentScan}, {APIPermission::kEnterprisePlatformKeys, "enterprise.platformKeys"}, {APIPermission::kFileBrowserHandler, "fileBrowserHandler", diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp index 0fb9748..89a3580 100644 --- a/chromeos/chromeos.gyp +++ b/chromeos/chromeos.gyp @@ -523,6 +523,8 @@ 'cryptohome/mock_homedir_methods.h', 'dbus/mock_cryptohome_client.cc', 'dbus/mock_cryptohome_client.h', + 'dbus/mock_lorgnette_manager_client.cc', + 'dbus/mock_lorgnette_manager_client.h', 'dbus/mock_session_manager_client.cc', 'dbus/mock_session_manager_client.h', 'dbus/mock_shill_manager_client.cc', diff --git a/chromeos/dbus/mock_lorgnette_manager_client.cc b/chromeos/dbus/mock_lorgnette_manager_client.cc new file mode 100644 index 0000000..877a347 --- /dev/null +++ b/chromeos/dbus/mock_lorgnette_manager_client.cc @@ -0,0 +1,16 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mock_lorgnette_manager_client.h" + +namespace chromeos { + +MockLorgnetteManagerClient::MockLorgnetteManagerClient() { +} + +MockLorgnetteManagerClient::~MockLorgnetteManagerClient() { +} + +} // namespace chromeos + diff --git a/chromeos/dbus/mock_lorgnette_manager_client.h b/chromeos/dbus/mock_lorgnette_manager_client.h new file mode 100644 index 0000000..df80f5f3 --- /dev/null +++ b/chromeos/dbus/mock_lorgnette_manager_client.h @@ -0,0 +1,29 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_DBUS_MOCK_LORGNETTE_MANAGER_CLIENT_H_ +#define CHROMEOS_DBUS_MOCK_LORGNETTE_MANAGER_CLIENT_H_ + +#include "lorgnette_manager_client.h" + +#include <gmock/gmock.h> + +namespace chromeos { + +class MockLorgnetteManagerClient : public LorgnetteManagerClient { + public: + MockLorgnetteManagerClient(); + virtual ~MockLorgnetteManagerClient(); + + MOCK_METHOD1(ListScanners, void(const ListScannersCallback& callback)); + MOCK_METHOD4(ScanImage, void(std::string device_name, + base::PlatformFile file, + const ScanProperties& properties, + const ScanImageCallback& callback)); + MOCK_METHOD1(Init, void(dbus::Bus* bus)); +}; + +} // namespace chromeos + +#endif // CHROMEOS_DBUS_MOCK_LORGNETTE_MANAGER_CLIENT_H_ diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index 8d0b10c..45b0d6f 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h @@ -969,6 +969,7 @@ enum HistogramValue { INPUTMETHODPRIVATE_GETINPUTMETHODCONFIG, WALLPAPERPRIVATE_GETSYNCSETTING, COPRESENCE_SETAUTHTOKEN, + DOCUMENT_SCAN_SCAN, // Last entry: Add new entries above and ensure to update // tools/metrics/histograms/histograms.xml. ENUM_BOUNDARY diff --git a/extensions/common/permissions/api_permission.h b/extensions/common/permissions/api_permission.h index fbb34d1..c60ba75 100644 --- a/extensions/common/permissions/api_permission.h +++ b/extensions/common/permissions/api_permission.h @@ -53,6 +53,7 @@ class APIPermission { kBookmark, kBookmarkManagerPrivate, kBrailleDisplayPrivate, + kBrowser, kBrowsingData, kCast, kCastStreaming, @@ -77,6 +78,7 @@ class APIPermission { kDeveloperPrivate, kDevtools, kDns, + kDocumentScan, kDownloads, kDownloadsInternal, kDownloadsOpen, @@ -99,6 +101,7 @@ class APIPermission { kFileSystemRetainEntries, kFileSystemWrite, kFileSystemWriteDirectory, + kFirstRunPrivate, kFontSettings, kFullscreen, kGcdPrivate, @@ -188,8 +191,6 @@ class APIPermission { kSystemNetwork, kSystemInfoCpu, kSystemInfoMemory, - kFirstRunPrivate, - kBrowser, kEnumBoundary }; diff --git a/extensions/common/permissions/permission_message.h b/extensions/common/permissions/permission_message.h index 25eda75..2df53e3 100644 --- a/extensions/common/permissions/permission_message.h +++ b/extensions/common/permissions/permission_message.h @@ -90,6 +90,9 @@ class PermissionMessage { kCopresence, kTopSites, kU2fDevices, + kDocumentScan, + // Last entry: Add new entries above and ensure to update the + // "ExtensionPermission2" enum in tools/metrics/histograms/histograms.xml. kEnumBoundary, }; COMPILE_ASSERT(PermissionMessage::kNone > PermissionMessage::kUnknown, diff --git a/extensions/extensions_strings.grd b/extensions/extensions_strings.grd index f2f09c7..4106ab7 100644 --- a/extensions/extensions_strings.grd +++ b/extensions/extensions_strings.grd @@ -174,6 +174,11 @@ <release seq="1" allow_pseudo="false"> <messages fallback_to_english="true"> + <!-- Document Scan API strings. Please keep alphabetized. --> + <message name="IDS_EXTENSION_PROMPT_WARNING_DOCUMENT_SCAN" desc="Permission string for access to document scanning."> + Access document scanners attached via USB or on the local network + </message> + <!-- General extensions strings. Please keep alphabetized. --> <message name="IDS_EXTENSION_CONTAINS_PRIVATE_KEY" desc="Error message when an extension includes a file containing a private key."> This extension includes the key file '<ph name="KEY_PATH">$1<ex>relative/path/to/file.pem</ex></ph>'. You probably don't want to do that. diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 096f76d..4c02d5e 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -43417,6 +43417,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="908" label="INPUTMETHODPRIVATE_GETINPUTMETHODCONFIG"/> <int value="909" label="WALLPAPERPRIVATE_GETSYNCSETTING"/> <int value="910" label="COPRESENCE_SETAUTHTOKEN"/> + <int value="911" label="DOCUMENT_SCAN_SCAN"/> </enum> <enum name="ExtensionInstallCause" type="int"> @@ -43598,6 +43599,12 @@ Therefore, the affected-histogram name has to have at least one dot in it. <int value="60" label="kAccessibilityFeaturesModify"/> <int value="61" label="kAccessibilityFeaturesRead"/> <int value="62" label="kBluetoothPrivate"/> + <int value="63" label="kIdentityEmail"/> + <int value="64" label="kExperienceSamplingPrivate"/> + <int value="65" label="kCopresence"/> + <int value="66" label="kTopSites"/> + <int value="67" label="kU2fDevices"/> + <int value="68" label="kDocumentScan"/> </enum> <enum name="ExtensionServiceVerifyAllSuccess" type="int"> |