1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chromeos/dbus/lorgnette_manager_client.h"
10 #include "base/bind_helpers.h"
11 #include "base/location.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/task_runner_util.h"
14 #include "base/threading/worker_pool.h"
15 #include "chromeos/dbus/pipe_reader.h"
17 #include "dbus/message.h"
18 #include "dbus/object_path.h"
19 #include "dbus/object_proxy.h"
20 #include "net/base/file_stream.h"
21 #include "third_party/cros_system_api/dbus/service_constants.h"
25 // The LorgnetteManagerClient implementation used in production.
26 class LorgnetteManagerClientImpl
: public LorgnetteManagerClient
{
28 LorgnetteManagerClientImpl() :
29 lorgnette_daemon_proxy_(NULL
), weak_ptr_factory_(this) {}
31 ~LorgnetteManagerClientImpl() override
{}
33 void ListScanners(const ListScannersCallback
& callback
) override
{
34 dbus::MethodCall
method_call(lorgnette::kManagerServiceInterface
,
35 lorgnette::kListScannersMethod
);
36 lorgnette_daemon_proxy_
->CallMethod(
38 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
39 base::Bind(&LorgnetteManagerClientImpl::OnListScanners
,
40 weak_ptr_factory_
.GetWeakPtr(),
44 // LorgnetteManagerClient override.
46 std::string device_name
,
47 const ScanProperties
& properties
,
48 const ScanImageToFileCallback
& callback
,
49 base::File
* file
) override
{
50 dbus::FileDescriptor
* file_descriptor
= new dbus::FileDescriptor();
51 file_descriptor
->PutValue(file
->TakePlatformFile());
52 // Punt descriptor validity check to a worker thread; on return we'll
53 // issue the D-Bus request to stop tracing and collect results.
54 base::WorkerPool::PostTaskAndReply(
56 base::Bind(&LorgnetteManagerClientImpl::CheckValidity
,
58 base::Bind(&LorgnetteManagerClientImpl::OnCheckValidityScanImage
,
59 weak_ptr_factory_
.GetWeakPtr(),
60 base::Owned(file_descriptor
),
67 void ScanImageToString(
68 std::string device_name
,
69 const ScanProperties
& properties
,
70 const ScanImageToStringCallback
& callback
) override
{
71 // Owned by the callback created in scan_to_string_completion->Start().
72 ScanToStringCompletion
* scan_to_string_completion
=
73 new ScanToStringCompletion();
75 ScanImageToFileCallback file_callback
=
76 scan_to_string_completion
->Start(callback
, &file
);
77 ScanImageToFile(device_name
, properties
, file_callback
, &file
);
81 void Init(dbus::Bus
* bus
) override
{
82 lorgnette_daemon_proxy_
=
83 bus
->GetObjectProxy(lorgnette::kManagerServiceName
,
84 dbus::ObjectPath(lorgnette::kManagerServicePath
));
88 class ScanToStringCompletion
{
90 ScanToStringCompletion() {}
91 virtual ~ScanToStringCompletion() {}
93 // Creates a file stream in |file| that will stream image data to
94 // a string that will be supplied to |callback|. Passes ownership
95 // of |this| to a returned callback that can be handed to a
96 // ScanImageToFile invocation.
97 ScanImageToFileCallback
Start(const ScanImageToStringCallback
& callback
,
99 CHECK(!pipe_reader_
.get());
100 const bool kTasksAreSlow
= true;
101 scoped_refptr
<base::TaskRunner
> task_runner
=
102 base::WorkerPool::GetTaskRunner(kTasksAreSlow
);
104 new chromeos::PipeReaderForString(
106 base::Bind(&ScanToStringCompletion::OnScanToStringDataCompleted
,
107 base::Unretained(this))));
108 *file
= pipe_reader_
->StartIO();
110 return base::Bind(&ScanToStringCompletion::OnScanToStringCompleted
,
111 base::Owned(this), callback
);
115 // Called when a |pipe_reader_| completes reading scan data to a string.
116 void OnScanToStringDataCompleted() {
117 pipe_reader_
->GetData(&scanned_image_data_string_
);
118 pipe_reader_
.reset();
121 // Called by LorgnetteManagerImpl when scan completes.
122 void OnScanToStringCompleted(const ScanImageToStringCallback
& callback
,
124 if (pipe_reader_
.get()) {
125 pipe_reader_
->OnDataReady(-1); // terminate data stream
127 callback
.Run(succeeded
, scanned_image_data_string_
);
128 scanned_image_data_string_
.clear();
131 scoped_ptr
<chromeos::PipeReaderForString
> pipe_reader_
;
132 std::string scanned_image_data_string_
;
134 DISALLOW_COPY_AND_ASSIGN(ScanToStringCompletion
);
137 // Called when ListScanners completes.
138 void OnListScanners(const ListScannersCallback
& callback
,
139 dbus::Response
* response
) {
140 ScannerTable scanners
;
141 dbus::MessageReader
table_reader(NULL
);
142 if (!response
|| !dbus::MessageReader(response
).PopArray(&table_reader
)) {
143 callback
.Run(false, scanners
);
147 bool decode_failure
= false;
148 while (table_reader
.HasMoreData()) {
149 std::string device_name
;
150 dbus::MessageReader
device_entry_reader(NULL
);
151 dbus::MessageReader
device_element_reader(NULL
);
152 if (!table_reader
.PopDictEntry(&device_entry_reader
) ||
153 !device_entry_reader
.PopString(&device_name
) ||
154 !device_entry_reader
.PopArray(&device_element_reader
)) {
155 decode_failure
= true;
159 ScannerTableEntry scanner_entry
;
160 while (device_element_reader
.HasMoreData()) {
161 dbus::MessageReader
device_attribute_reader(NULL
);
162 std::string attribute
;
164 if (!device_element_reader
.PopDictEntry(&device_attribute_reader
) ||
165 !device_attribute_reader
.PopString(&attribute
) ||
166 !device_attribute_reader
.PopString(&value
)) {
167 decode_failure
= true;
170 scanner_entry
[attribute
] = value
;
176 scanners
[device_name
] = scanner_entry
;
179 if (decode_failure
) {
180 LOG(ERROR
) << "Failed to decode response from ListScanners";
181 callback
.Run(false, scanners
);
183 callback
.Run(true, scanners
);
187 // Called to check descriptor validity on a thread where i/o is permitted.
188 static void CheckValidity(dbus::FileDescriptor
* file_descriptor
) {
189 file_descriptor
->CheckValidity();
192 // Called when a CheckValidity response is received.
193 void OnCheckValidityScanImage(
194 dbus::FileDescriptor
* file_descriptor
,
195 std::string device_name
,
196 const ScanProperties
& properties
,
197 const ScanImageToFileCallback
& callback
) {
198 if (!file_descriptor
->is_valid()) {
199 LOG(ERROR
) << "Failed to scan image: file descriptor is invalid";
203 // Issue the dbus request to scan an image.
204 dbus::MethodCall
method_call(
205 lorgnette::kManagerServiceInterface
,
206 lorgnette::kScanImageMethod
);
207 dbus::MessageWriter
writer(&method_call
);
208 writer
.AppendString(device_name
);
209 writer
.AppendFileDescriptor(*file_descriptor
);
211 dbus::MessageWriter
option_writer(NULL
);
212 dbus::MessageWriter
element_writer(NULL
);
213 writer
.OpenArray("{sv}", &option_writer
);
214 if (!properties
.mode
.empty()) {
215 option_writer
.OpenDictEntry(&element_writer
);
216 element_writer
.AppendString(lorgnette::kScanPropertyMode
);
217 element_writer
.AppendVariantOfString(properties
.mode
);
218 option_writer
.CloseContainer(&element_writer
);
220 if (properties
.resolution_dpi
) {
221 option_writer
.OpenDictEntry(&element_writer
);
222 element_writer
.AppendString(lorgnette::kScanPropertyResolution
);
223 element_writer
.AppendVariantOfUint32(properties
.resolution_dpi
);
224 option_writer
.CloseContainer(&element_writer
);
226 writer
.CloseContainer(&option_writer
);
228 lorgnette_daemon_proxy_
->CallMethod(
230 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
231 base::Bind(&LorgnetteManagerClientImpl::OnScanImageComplete
,
232 weak_ptr_factory_
.GetWeakPtr(),
236 // Called when a response for ScanImage() is received.
237 void OnScanImageComplete(const ScanImageToFileCallback
& callback
,
238 dbus::Response
* response
) {
240 LOG(ERROR
) << "Failed to scan image";
247 dbus::ObjectProxy
* lorgnette_daemon_proxy_
;
248 base::WeakPtrFactory
<LorgnetteManagerClientImpl
> weak_ptr_factory_
;
250 DISALLOW_COPY_AND_ASSIGN(LorgnetteManagerClientImpl
);
253 LorgnetteManagerClient::LorgnetteManagerClient() {
256 LorgnetteManagerClient::~LorgnetteManagerClient() {
260 LorgnetteManagerClient
* LorgnetteManagerClient::Create() {
261 return new LorgnetteManagerClientImpl();
264 } // namespace chromeos