| OLD | NEW |
| 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 <set> | 8 #include <set> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <utility> | 10 #include <utility> |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 | 113 |
| 114 content::Details<::printing::JobEventDetails> job_details(details); | 114 content::Details<::printing::JobEventDetails> job_details(details); |
| 115 | 115 |
| 116 // DOC_DONE occurs after the print job has been successfully sent to the | 116 // DOC_DONE occurs after the print job has been successfully sent to the |
| 117 // spooler which is when we begin tracking the print queue. | 117 // spooler which is when we begin tracking the print queue. |
| 118 if (job_details->type() == ::printing::JobEventDetails::DOC_DONE) { | 118 if (job_details->type() == ::printing::JobEventDetails::DOC_DONE) { |
| 119 const ::printing::PrintedDocument* document = job_details->document(); | 119 const ::printing::PrintedDocument* document = job_details->document(); |
| 120 DCHECK(document); | 120 DCHECK(document); |
| 121 CreatePrintJob(base::UTF16ToUTF8(document->settings().device_name()), | 121 CreatePrintJob(base::UTF16ToUTF8(document->settings().device_name()), |
| 122 base::UTF16ToUTF8(document->settings().title()), | 122 base::UTF16ToUTF8(document->settings().title()), |
| 123 document->page_count()); | 123 job_details->job_id(), document->page_count()); |
| 124 } | 124 } |
| 125 } | 125 } |
| 126 | 126 |
| 127 bool CupsPrintJobManagerImpl::CreatePrintJob(const std::string& printer_name, | 127 bool CupsPrintJobManagerImpl::CreatePrintJob(const std::string& printer_name, |
| 128 const std::string& title, | 128 const std::string& title, |
| 129 int job_id, |
| 129 int total_page_number) { | 130 int total_page_number) { |
| 130 // Of the current jobs, find the new one for the printer. | |
| 131 ::printing::CupsJob* new_job = nullptr; | |
| 132 std::vector<::printing::CupsJob> cups_jobs = cups_connection_.GetJobs(); | |
| 133 for (auto& job : cups_jobs) { | |
| 134 if (printer_name == job.printer_id && | |
| 135 !JobFinished(ConvertState(job.state)) && | |
| 136 !base::ContainsKey(jobs_, | |
| 137 CupsPrintJob::GetUniqueId(printer_name, job.id))) { | |
| 138 // We found an untracked job. It should be ours. | |
| 139 new_job = &job; | |
| 140 break; | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 // The started job cannot be found in the queue. | |
| 145 if (!new_job) { | |
| 146 LOG(WARNING) << "Could not track print job."; | |
| 147 return false; | |
| 148 } | |
| 149 | |
| 150 auto printer = | 131 auto printer = |
| 151 chromeos::PrintersManagerFactory::GetForBrowserContext(profile_) | 132 chromeos::PrintersManagerFactory::GetForBrowserContext(profile_) |
| 152 ->GetPrinter(printer_name); | 133 ->GetPrinter(printer_name); |
| 153 if (!printer) { | 134 if (!printer) { |
| 154 LOG(WARNING) << "Printer was removed while job was in progress. It cannot " | 135 LOG(WARNING) << "Printer was removed while job was in progress. It cannot " |
| 155 "be tracked"; | 136 "be tracked"; |
| 156 return false; | 137 return false; |
| 157 } | 138 } |
| 158 | 139 |
| 159 // Create a new print job. | 140 // Create a new print job. |
| 160 auto cpj = base::MakeUnique<CupsPrintJob>(*printer, new_job->id, title, | 141 auto cpj = base::MakeUnique<CupsPrintJob>(*printer, job_id, title, |
| 161 total_page_number); | 142 total_page_number); |
| 162 std::string key = cpj->GetUniqueId(); | 143 std::string key = cpj->GetUniqueId(); |
| 163 jobs_[key] = std::move(cpj); | 144 jobs_[key] = std::move(cpj); |
| 164 NotifyJobCreated(jobs_[key].get()); | 145 CupsPrintJob* job = jobs_[key].get(); |
| 146 NotifyJobCreated(job); |
| 165 | 147 |
| 166 JobStateUpdated(jobs_[key].get(), ConvertState(new_job->state)); | 148 // Always start jobs in the waiting state. |
| 149 job->set_state(CupsPrintJob::State::STATE_WAITING); |
| 150 NotifyJobUpdated(job); |
| 167 | 151 |
| 168 ScheduleQuery(); | 152 ScheduleQuery(base::TimeDelta()); |
| 169 | 153 |
| 170 return true; | 154 return true; |
| 171 } | 155 } |
| 172 | 156 |
| 173 void CupsPrintJobManagerImpl::ScheduleQuery() { | 157 void CupsPrintJobManagerImpl::ScheduleQuery() { |
| 174 content::BrowserThread::PostDelayedTask( | 158 ScheduleQuery(base::TimeDelta::FromMilliseconds(kPollRate)); |
| 175 content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE, | 159 } |
| 176 base::Bind(&CupsPrintJobManagerImpl::QueryCups, | 160 |
| 177 weak_ptr_factory_.GetWeakPtr()), | 161 void CupsPrintJobManagerImpl::ScheduleQuery(const base::TimeDelta& delay) { |
| 178 base::TimeDelta::FromMilliseconds(kPollRate)); | 162 if (!in_query_) { |
| 163 in_query_ = true; |
| 164 content::BrowserThread::PostDelayedTask( |
| 165 content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE, |
| 166 base::Bind(&CupsPrintJobManagerImpl::QueryCups, |
| 167 weak_ptr_factory_.GetWeakPtr()), |
| 168 base::TimeDelta::FromMilliseconds(kPollRate)); |
| 169 } |
| 179 } | 170 } |
| 180 | 171 |
| 181 // Query CUPS asynchronously. Post results back to UI thread. | 172 // Query CUPS asynchronously. Post results back to UI thread. |
| 182 void CupsPrintJobManagerImpl::QueryCups() { | 173 void CupsPrintJobManagerImpl::QueryCups() { |
| 183 std::vector<::printing::CupsJob> jobs = cups_connection_.GetJobs(); | 174 std::vector<::printing::CupsJob> jobs = cups_connection_.GetJobs(); |
| 184 | 175 |
| 185 content::BrowserThread::PostTask( | 176 content::BrowserThread::PostTask( |
| 186 content::BrowserThread::ID::UI, FROM_HERE, | 177 content::BrowserThread::ID::UI, FROM_HERE, |
| 187 base::Bind(&CupsPrintJobManagerImpl::UpdateJobs, | 178 base::Bind(&CupsPrintJobManagerImpl::UpdateJobs, |
| 188 weak_ptr_factory_.GetWeakPtr(), jobs)); | 179 weak_ptr_factory_.GetWeakPtr(), jobs)); |
| 189 } | 180 } |
| 190 | 181 |
| 191 // Use job information to update local job states. Previously completed jobs | 182 // Use job information to update local job states. Previously completed jobs |
| 192 // could be in |jobs| but those are ignored as we will not emit updates for them | 183 // could be in |jobs| but those are ignored as we will not emit updates for them |
| 193 // after they are completed. | 184 // after they are completed. |
| 194 void CupsPrintJobManagerImpl::UpdateJobs( | 185 void CupsPrintJobManagerImpl::UpdateJobs( |
| 195 const std::vector<::printing::CupsJob>& jobs) { | 186 const std::vector<::printing::CupsJob>& jobs) { |
| 187 in_query_ = false; |
| 188 |
| 189 std::vector<std::string> active_jobs; |
| 196 for (auto& job : jobs) { | 190 for (auto& job : jobs) { |
| 197 std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id); | 191 std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id); |
| 198 const auto& entry = jobs_.find(key); | 192 const auto& entry = jobs_.find(key); |
| 199 if (entry != jobs_.end()) { | 193 if (entry != jobs_.end()) { |
| 200 CupsPrintJob* print_job = entry->second.get(); | 194 CupsPrintJob* print_job = entry->second.get(); |
| 201 | 195 |
| 202 // Update a job we're tracking. | 196 // Update a job we're tracking. |
| 203 JobStateUpdated(print_job, ConvertState(job.state)); | 197 JobStateUpdated(print_job, ConvertState(job.state)); |
| 204 | 198 |
| 205 // Cleanup completed jobs. | 199 // Cleanup completed jobs. |
| 206 if (JobFinished(print_job->state())) { | 200 if (JobFinished(print_job->state())) { |
| 207 jobs_.erase(entry); | 201 jobs_.erase(entry); |
| 202 } else { |
| 203 active_jobs.push_back(key); |
| 208 } | 204 } |
| 209 } | 205 } |
| 210 } | 206 } |
| 211 | 207 |
| 212 // Keep polling until all jobs complete or error. | 208 // Keep polling until all jobs complete or error. |
| 213 if (!jobs_.empty()) | 209 if (!active_jobs.empty()) { |
| 214 ScheduleQuery(); | 210 ScheduleQuery(); |
| 211 } else if (!jobs_.empty()) { |
| 212 // We're tracking jobs that we didn't receive an update for. Something bad |
| 213 // has happened. |
| 214 LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs"; |
| 215 for (const auto& entry : jobs_) { |
| 216 // Declare all lost jobs errors. |
| 217 JobStateUpdated(entry.second.get(), CupsPrintJob::State::STATE_ERROR); |
| 218 } |
| 219 |
| 220 jobs_.clear(); |
| 221 } |
| 215 } | 222 } |
| 216 | 223 |
| 217 void CupsPrintJobManagerImpl::JobStateUpdated(CupsPrintJob* job, | 224 void CupsPrintJobManagerImpl::JobStateUpdated(CupsPrintJob* job, |
| 218 CupsPrintJob::State new_state) { | 225 CupsPrintJob::State new_state) { |
| 219 if (job->state() == new_state) | 226 if (job->state() == new_state) |
| 220 return; | 227 return; |
| 221 | 228 |
| 222 // We don't track state transitions because some of them might be missed due | 229 // We don't track state transitions because some of them might be missed due |
| 223 // to how we query jobs. | 230 // to how we query jobs. |
| 224 job->set_state(new_state); | 231 job->set_state(new_state); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 252 break; | 259 break; |
| 253 } | 260 } |
| 254 } | 261 } |
| 255 | 262 |
| 256 // static | 263 // static |
| 257 CupsPrintJobManager* CupsPrintJobManager::CreateInstance(Profile* profile) { | 264 CupsPrintJobManager* CupsPrintJobManager::CreateInstance(Profile* profile) { |
| 258 return new CupsPrintJobManagerImpl(profile); | 265 return new CupsPrintJobManagerImpl(profile); |
| 259 } | 266 } |
| 260 | 267 |
| 261 } // namespace chromeos | 268 } // namespace chromeos |
| OLD | NEW |