summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/api/document_scan/document_scan_api.cc119
-rw-r--r--chrome/browser/extensions/api/document_scan/document_scan_api.h55
-rw-r--r--chrome/browser/extensions/api/document_scan/document_scan_api_unittest.cc123
-rw-r--r--chrome/browser/extensions/api/document_scan/document_scan_interface.cc26
-rw-r--r--chrome/browser/extensions/api/document_scan/document_scan_interface.h64
-rw-r--r--chrome/browser/extensions/api/document_scan/document_scan_interface_chromeos.cc161
-rw-r--r--chrome/browser/extensions/api/document_scan/document_scan_interface_chromeos.h51
-rw-r--r--chrome/browser/extensions/api/document_scan/document_scan_interface_chromeos_unittest.cc168
-rw-r--r--chrome/browser/extensions/api/document_scan/document_scan_interface_nonchromeos.cc44
-rw-r--r--chrome/browser/extensions/api/document_scan/mock_document_scan_interface.cc20
-rw-r--r--chrome/browser/extensions/api/document_scan/mock_document_scan_interface.h35
-rw-r--r--chrome/chrome_browser_extensions.gypi6
-rw-r--r--chrome/chrome_tests_unit.gypi3
-rw-r--r--chrome/common/extensions/api/_api_features.json5
-rw-r--r--chrome/common/extensions/api/_permission_features.json4
-rw-r--r--chrome/common/extensions/api/document_scan.idl36
-rw-r--r--chrome/common/extensions/api/schemas.gypi1
-rw-r--r--chrome/common/extensions/docs/examples/api/document_scan/README.md10
-rw-r--r--chrome/common/extensions/docs/examples/api/document_scan/background.js14
-rw-r--r--chrome/common/extensions/docs/examples/api/document_scan/manifest.json13
-rw-r--r--chrome/common/extensions/docs/examples/api/document_scan/scan.css37
-rw-r--r--chrome/common/extensions/docs/examples/api/document_scan/scan.html18
-rw-r--r--chrome/common/extensions/docs/examples/api/document_scan/scan.js69
-rw-r--r--chrome/common/extensions/permissions/chrome_api_permissions.cc3
-rw-r--r--chromeos/chromeos.gyp2
-rw-r--r--chromeos/dbus/mock_lorgnette_manager_client.cc16
-rw-r--r--chromeos/dbus/mock_lorgnette_manager_client.h29
-rw-r--r--extensions/browser/extension_function_histogram_value.h1
-rw-r--r--extensions/common/permissions/api_permission.h5
-rw-r--r--extensions/common/permissions/permission_message.h3
-rw-r--r--extensions/extensions_strings.grd5
-rw-r--r--tools/metrics/histograms/histograms.xml7
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">