Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(149)

Side by Side Diff: chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc

Issue 2705333007: Refine notifications for print jobs in progress. (Closed)
Patch Set: address comment from xdai Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/chromeos/printing/cups_print_job_manager_impl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/printing/cups_print_job_manager_impl.h" 5 #include "chrome/browser/chromeos/printing/cups_print_job_manager_impl.h"
6 6
7 #include <cups/cups.h> 7 #include <cups/cups.h>
8 #include <algorithm>
8 #include <set> 9 #include <set>
9 #include <string> 10 #include <string>
10 #include <utility> 11 #include <utility>
11 #include <vector> 12 #include <vector>
12 13
13 #include "base/bind.h" 14 #include "base/bind.h"
14 #include "base/memory/ptr_util.h" 15 #include "base/memory/ptr_util.h"
15 #include "base/stl_util.h" 16 #include "base/stl_util.h"
16 #include "base/strings/utf_string_conversions.h" 17 #include "base/strings/utf_string_conversions.h"
17 #include "base/threading/sequenced_task_runner_handle.h" 18 #include "base/threading/sequenced_task_runner_handle.h"
18 #include "chrome/browser/chrome_notification_types.h" 19 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/chromeos/printing/cups_print_job.h" 20 #include "chrome/browser/chromeos/printing/cups_print_job.h"
20 #include "chrome/browser/chromeos/printing/printers_manager.h" 21 #include "chrome/browser/chromeos/printing/printers_manager.h"
21 #include "chrome/browser/chromeos/printing/printers_manager_factory.h" 22 #include "chrome/browser/chromeos/printing/printers_manager_factory.h"
22 #include "chrome/browser/printing/print_job.h" 23 #include "chrome/browser/printing/print_job.h"
23 #include "chrome/browser/profiles/profile.h" 24 #include "chrome/browser/profiles/profile.h"
24 #include "content/public/browser/browser_context.h" 25 #include "content/public/browser/browser_context.h"
25 #include "content/public/browser/browser_thread.h" 26 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/notification_registrar.h" 27 #include "content/public/browser/notification_registrar.h"
27 #include "content/public/browser/notification_service.h" 28 #include "content/public/browser/notification_service.h"
28 #include "printing/backend/cups_connection.h" 29 #include "printing/backend/cups_connection.h"
29 #include "printing/printed_document.h" 30 #include "printing/printed_document.h"
30 31
31 namespace { 32 namespace {
32 33
33 // The rate in milliseconds at which we will poll CUPS for print job updates. 34 // The rate in milliseconds at which we will poll CUPS for print job updates.
34 const int kPollRate = 1000; 35 const int kPollRate = 1000;
35 36
37 // How long we'll wait to connect to a printer before declaring an error.
38 const int kConnectingTimeout = 20;
39
36 // Threshold for giving up on communicating with CUPS. 40 // Threshold for giving up on communicating with CUPS.
37 const int kRetryMax = 6; 41 const int kRetryMax = 6;
38 42
43 using State = chromeos::CupsPrintJob::State;
44 using ErrorCode = chromeos::CupsPrintJob::ErrorCode;
45
46 using PrinterReason = printing::PrinterStatus::PrinterReason;
47
39 // Returns the equivalient CupsPrintJob#State from a CupsJob#JobState. 48 // Returns the equivalient CupsPrintJob#State from a CupsJob#JobState.
40 chromeos::CupsPrintJob::State ConvertState(printing::CupsJob::JobState state) { 49 chromeos::CupsPrintJob::State ConvertState(printing::CupsJob::JobState state) {
41 using cpj = chromeos::CupsPrintJob::State;
42
43 switch (state) { 50 switch (state) {
44 case printing::CupsJob::PENDING: 51 case printing::CupsJob::PENDING:
45 return cpj::STATE_WAITING; 52 return State::STATE_WAITING;
46 case printing::CupsJob::HELD: 53 case printing::CupsJob::HELD:
47 return cpj::STATE_SUSPENDED; 54 return State::STATE_SUSPENDED;
48 case printing::CupsJob::PROCESSING: 55 case printing::CupsJob::PROCESSING:
49 return cpj::STATE_STARTED; 56 return State::STATE_STARTED;
50 case printing::CupsJob::CANCELED: 57 case printing::CupsJob::CANCELED:
51 return cpj::STATE_CANCELLED; 58 return State::STATE_CANCELLED;
52 case printing::CupsJob::COMPLETED: 59 case printing::CupsJob::COMPLETED:
53 return cpj::STATE_DOCUMENT_DONE; 60 return State::STATE_DOCUMENT_DONE;
54 case printing::CupsJob::STOPPED: 61 case printing::CupsJob::STOPPED:
55 return cpj::STATE_SUSPENDED; 62 return State::STATE_SUSPENDED;
56 case printing::CupsJob::ABORTED: 63 case printing::CupsJob::ABORTED:
57 return cpj::STATE_ERROR; 64 return State::STATE_ERROR;
58 case printing::CupsJob::UNKNOWN: 65 case printing::CupsJob::UNKNOWN:
59 break; 66 break;
60 } 67 }
61 68
62 NOTREACHED(); 69 NOTREACHED();
63 70
64 return cpj::STATE_NONE; 71 return State::STATE_NONE;
65 } 72 }
66 73
67 chromeos::QueryResult QueryCups(::printing::CupsConnection* connection, 74 chromeos::QueryResult QueryCups(::printing::CupsConnection* connection,
68 const std::vector<std::string>& printer_ids) { 75 const std::vector<std::string>& printer_ids) {
69 chromeos::QueryResult result; 76 chromeos::QueryResult result;
70 result.success = connection->GetJobs(printer_ids, &result.queues); 77 result.success = connection->GetJobs(printer_ids, &result.queues);
71 return result; 78 return result;
72 } 79 }
73 80
81 // Returns true if |printer_status|.reasons contains |reason|.
82 bool ContainsReason(const printing::PrinterStatus printer_status,
83 PrinterReason::Reason reason) {
84 return std::find_if(
85 printer_status.reasons.begin(), printer_status.reasons.end(),
86 [reason](const PrinterReason& r) { return r.reason == reason; }) !=
Carlson 2017/03/14 17:10:36 I think this can be [&reason], but I don't know if
skau 2017/03/14 21:32:07 Both parts of your statement are true. I changed
87 printer_status.reasons.end();
88 }
89
90 // Returns true if the reason is paper related.
91 bool IsPaperReason(const PrinterReason& reason) {
92 static std::set<PrinterReason::Reason> paper_reasons = {
93 PrinterReason::MEDIA_JAM, PrinterReason::MEDIA_EMPTY,
94 PrinterReason::MEDIA_NEEDED, PrinterReason::MEDIA_LOW};
95
96 return paper_reasons.find(reason.reason) != paper_reasons.end();
97 }
98
99 // Returns true if the reason is ink related.
100 bool IsInkReason(const PrinterReason& reason) {
101 return reason.reason == PrinterReason::TONER_EMPTY ||
102 reason.reason == PrinterReason::TONER_LOW;
103 }
104
105 // Extracts an ErrorCode from PrinterStatus#reasons. Returns NO_ERROR if there
106 // are no reasons which indicate an error.
107 chromeos::CupsPrintJob::ErrorCode ErrorCodeFromReasons(
108 const printing::PrinterStatus& printer_status) {
109 const auto begin = printer_status.reasons.begin();
110 const auto end = printer_status.reasons.end();
111
112 if (std::find_if(begin, end, &IsPaperReason) != end) {
Carlson 2017/03/14 17:10:36 This seems odd to me. Do you really want the hi
skau 2017/03/14 21:32:07 Switched to a switch.
113 return chromeos::CupsPrintJob::ErrorCode::PAPER_JAM;
114 } else if (std::find_if(begin, end, &IsInkReason) != end) {
115 return chromeos::CupsPrintJob::ErrorCode::OUT_OF_INK;
116 }
117
118 return chromeos::CupsPrintJob::ErrorCode::NO_ERROR;
119 }
120
121 // Update job in the processing state. Returns true if the number of pages
122 // changed.
123 bool UpdateForProcessing(const printing::PrinterStatus& printer_status,
124 const printing::CupsJob& job,
125 chromeos::CupsPrintJob* print_job) {
126 if (ContainsReason(printer_status, PrinterReason::CONNECTING_TO_DEVICE)) {
127 // Check to see if we should time out.
128 base::TimeDelta time_waiting =
129 base::Time::Now() - base::Time::FromTimeT(job.processing_started);
130 if (time_waiting > base::TimeDelta::FromSeconds(kConnectingTimeout)) {
131 print_job->set_state(chromeos::CupsPrintJob::State::STATE_ERROR);
132 print_job->set_error_code(
133 chromeos::CupsPrintJob::ErrorCode::PRINTER_UNREACHABLE);
134 LOG(WARNING) << "Connecting to printer timed out";
135 }
136
137 // Always return false from the CONNECTING_TO_DEVICE state since pages
138 // are never updated if we can't talk to the printer.
139 return false;
140 }
141
142 bool pages_updated = false;
143 if (job.current_pages <= 0) {
144 print_job->set_printed_page_number(0);
145 print_job->set_state(State::STATE_STARTED);
146 } else {
147 pages_updated = job.current_pages != print_job->printed_page_number();
148 print_job->set_printed_page_number(job.current_pages);
149 print_job->set_state(State::STATE_PAGE_DONE);
150 }
151
152 return pages_updated;
153 }
154
155 // Returns true if the state of |print_job| changed. Updates |print_job| with
Carlson 2017/03/14 17:10:36 I think the docstring about the return value is no
skau 2017/03/14 21:32:07 The boolean represents if we should notify observe
156 // the data in |printer_status| and |job|.
157 bool UpdatePrintJob(const printing::PrinterStatus& printer_status,
158 const printing::CupsJob& job,
159 chromeos::CupsPrintJob* print_job) {
160 DCHECK_EQ(job.id, print_job->job_id());
161
162 State old_state = print_job->state();
163
164 bool pages_updated = false;
165 switch (job.state) {
166 case printing::CupsJob::PROCESSING:
167 pages_updated = UpdateForProcessing(printer_status, job, print_job);
168 break;
169 case printing::CupsJob::COMPLETED:
170 DCHECK_GE(job.current_pages, print_job->total_page_number());
171 print_job->set_state(State::STATE_DOCUMENT_DONE);
172 break;
173 case printing::CupsJob::ABORTED:
174 case printing::CupsJob::CANCELED:
175 print_job->set_error_code(ErrorCodeFromReasons(printer_status));
176 // fall through
177 default:
178 print_job->set_state(ConvertState(job.state));
179 break;
180 }
181
182 return print_job->state() != old_state || pages_updated;
183 }
184
74 } // namespace 185 } // namespace
75 186
76 namespace chromeos { 187 namespace chromeos {
77 188
78 CupsPrintJobManagerImpl::CupsPrintJobManagerImpl(Profile* profile) 189 CupsPrintJobManagerImpl::CupsPrintJobManagerImpl(Profile* profile)
79 : CupsPrintJobManager(profile), 190 : CupsPrintJobManager(profile),
80 cups_connection_(GURL(), HTTP_ENCRYPT_NEVER, false), 191 cups_connection_(GURL(), HTTP_ENCRYPT_NEVER, false),
81 weak_ptr_factory_(this) { 192 weak_ptr_factory_(this) {
82 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, 193 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
83 content::NotificationService::AllSources()); 194 content::NotificationService::AllSources());
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 std::vector<std::string> active_jobs; 331 std::vector<std::string> active_jobs;
221 for (const auto& queue : queues) { 332 for (const auto& queue : queues) {
222 for (auto& job : queue.jobs) { 333 for (auto& job : queue.jobs) {
223 std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id); 334 std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id);
224 const auto& entry = jobs_.find(key); 335 const auto& entry = jobs_.find(key);
225 if (entry == jobs_.end()) 336 if (entry == jobs_.end())
226 continue; 337 continue;
227 338
228 CupsPrintJob* print_job = entry->second.get(); 339 CupsPrintJob* print_job = entry->second.get();
229 340
230 // Update a job we're tracking. 341 if (UpdatePrintJob(queue.printer_status, job, print_job)) {
231 JobStateUpdated(print_job, ConvertState(job.state)); 342 // The state of the job changed, notify observers.
343 NotifyJobStateUpdate(print_job);
344 }
232 345
233 // Cleanup completed jobs. 346 // Cleanup completed jobs.
234 if (print_job->IsJobFinished()) { 347 if (print_job->IsJobFinished()) {
235 jobs_.erase(entry); 348 jobs_.erase(entry);
236 } else { 349 } else {
237 active_jobs.push_back(key); 350 active_jobs.push_back(key);
238 } 351 }
239 } 352 }
240 } 353 }
241 354
242 // Keep polling until all jobs complete or error. 355 // Keep polling until all jobs complete or error.
243 if (!active_jobs.empty()) { 356 if (!active_jobs.empty()) {
244 // During normal operations, we poll at the default rate. 357 // During normal operations, we poll at the default rate.
245 ScheduleQuery(); 358 ScheduleQuery();
246 } else if (!jobs_.empty()) { 359 } else if (!jobs_.empty()) {
247 // We're tracking jobs that we didn't receive an update for. Something bad 360 // We're tracking jobs that we didn't receive an update for. Something bad
248 // has happened. 361 // has happened.
249 LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs"; 362 LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs";
250 PurgeJobs(); 363 PurgeJobs();
251 } 364 }
252 } 365 }
253 366
254 void CupsPrintJobManagerImpl::PurgeJobs() { 367 void CupsPrintJobManagerImpl::PurgeJobs() {
255 for (const auto& entry : jobs_) { 368 for (const auto& entry : jobs_) {
256 // Declare all lost jobs errors. 369 // Declare all lost jobs errors.
257 JobStateUpdated(entry.second.get(), CupsPrintJob::State::STATE_ERROR); 370 CupsPrintJob* job = entry.second.get();
371 job->set_state(CupsPrintJob::State::STATE_ERROR);
372 NotifyJobStateUpdate(job);
258 } 373 }
259 374
260 jobs_.clear(); 375 jobs_.clear();
261 } 376 }
262 377
263 void CupsPrintJobManagerImpl::JobStateUpdated(CupsPrintJob* job, 378 void CupsPrintJobManagerImpl::NotifyJobStateUpdate(CupsPrintJob* job) {
264 CupsPrintJob::State new_state) { 379 switch (job->state()) {
265 if (job->state() == new_state) 380 case State::STATE_NONE:
266 return;
267
268 // We don't track state transitions because some of them might be missed due
269 // to how we query jobs.
270 job->set_state(new_state);
271 switch (new_state) {
272 case CupsPrintJob::State::STATE_NONE:
273 // State does not require notification. 381 // State does not require notification.
274 break; 382 break;
275 case CupsPrintJob::State::STATE_WAITING: 383 case State::STATE_WAITING:
276 NotifyJobUpdated(job); 384 NotifyJobUpdated(job);
277 break; 385 break;
278 case CupsPrintJob::State::STATE_STARTED: 386 case State::STATE_STARTED:
279 NotifyJobStarted(job); 387 NotifyJobStarted(job);
280 break; 388 break;
281 case CupsPrintJob::State::STATE_RESUMED: 389 case State::STATE_PAGE_DONE:
390 NotifyJobUpdated(job);
391 break;
392 case State::STATE_RESUMED:
282 NotifyJobResumed(job); 393 NotifyJobResumed(job);
283 break; 394 break;
284 case CupsPrintJob::State::STATE_SUSPENDED: 395 case State::STATE_SUSPENDED:
285 NotifyJobSuspended(job); 396 NotifyJobSuspended(job);
286 break; 397 break;
287 case CupsPrintJob::State::STATE_CANCELLED: 398 case State::STATE_CANCELLED:
288 NotifyJobCanceled(job); 399 NotifyJobCanceled(job);
289 break; 400 break;
290 case CupsPrintJob::State::STATE_ERROR: 401 case State::STATE_ERROR:
291 NotifyJobError(job); 402 NotifyJobError(job);
292 break; 403 break;
293 case CupsPrintJob::State::STATE_PAGE_DONE: 404 case State::STATE_DOCUMENT_DONE:
294 NOTREACHED() << "CUPS does not surface this state so it's not expected";
295 break;
296 case CupsPrintJob::State::STATE_DOCUMENT_DONE:
297 NotifyJobDone(job); 405 NotifyJobDone(job);
298 break; 406 break;
299 } 407 }
300 } 408 }
301 409
302 // static 410 // static
303 CupsPrintJobManager* CupsPrintJobManager::CreateInstance(Profile* profile) { 411 CupsPrintJobManager* CupsPrintJobManager::CreateInstance(Profile* profile) {
304 return new CupsPrintJobManagerImpl(profile); 412 return new CupsPrintJobManagerImpl(profile);
305 } 413 }
306 414
307 } // namespace chromeos 415 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/printing/cups_print_job_manager_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698