1c36cf2e9Sopenharmony_ci/* 2c36cf2e9Sopenharmony_ci * Copyright (c) 2023-2023 Huawei Device Co., Ltd. 3c36cf2e9Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4c36cf2e9Sopenharmony_ci * you may not use this file except in compliance with the License. 5c36cf2e9Sopenharmony_ci * You may obtain a copy of the License at 6c36cf2e9Sopenharmony_ci * 7c36cf2e9Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8c36cf2e9Sopenharmony_ci * 9c36cf2e9Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10c36cf2e9Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11c36cf2e9Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12c36cf2e9Sopenharmony_ci * See the License for the specific language governing permissions and 13c36cf2e9Sopenharmony_ci * limitations under the License. 14c36cf2e9Sopenharmony_ci */ 15c36cf2e9Sopenharmony_ciimport CheckEmptyUtils, { Constants, convertToSpoolerPrintJob, isValidPrintJob, Log, PrintJob, PrintJobChangeListener, queryAllPrintJobs, SingletonHelper } from '@ohos/common'; 16c36cf2e9Sopenharmony_ciimport print from '@ohos.print'; 17c36cf2e9Sopenharmony_ciimport FileUtil from '../Common/Utils/FileUtil'; 18c36cf2e9Sopenharmony_ci 19c36cf2e9Sopenharmony_ciconst TAG: string = 'PrintJobManager'; 20c36cf2e9Sopenharmony_ciclass PrintJobManager { 21c36cf2e9Sopenharmony_ci private localJobMap: Map<string, PrintJob> = new Map(); 22c36cf2e9Sopenharmony_ci private isStarted: boolean = false; 23c36cf2e9Sopenharmony_ci private isRegister: boolean = false; 24c36cf2e9Sopenharmony_ci private printJobChangeListeners: Map<string, PrintJobChangeListener> = new Map(); 25c36cf2e9Sopenharmony_ci 26c36cf2e9Sopenharmony_ci private onJobStateChanged = (jobState: print.PrintJobState, job: print.PrintJob): void => { 27c36cf2e9Sopenharmony_ci Log.info(TAG, `onJobStateChanged jobId:${job?.jobId}, jobState:${jobState}, jobSubstate:${job?.jobSubstate}`); 28c36cf2e9Sopenharmony_ci if (!isValidPrintJob(job)) { 29c36cf2e9Sopenharmony_ci Log.warn(TAG, 'onJobStateChanged invalid job.'); 30c36cf2e9Sopenharmony_ci return; 31c36cf2e9Sopenharmony_ci } 32c36cf2e9Sopenharmony_ci let printJob: PrintJob = convertToSpoolerPrintJob(job); 33c36cf2e9Sopenharmony_ci this.deleteLocalSource(printJob); 34c36cf2e9Sopenharmony_ci this.updatePrintJob(printJob); 35c36cf2e9Sopenharmony_ci }; 36c36cf2e9Sopenharmony_ci 37c36cf2e9Sopenharmony_ci onStart(printerId?: string): void { 38c36cf2e9Sopenharmony_ci if (this.isStarted) { 39c36cf2e9Sopenharmony_ci return; 40c36cf2e9Sopenharmony_ci } 41c36cf2e9Sopenharmony_ci this.isStarted = true; 42c36cf2e9Sopenharmony_ci this.registerCallback(); 43c36cf2e9Sopenharmony_ci } 44c36cf2e9Sopenharmony_ci 45c36cf2e9Sopenharmony_ci onStop(): void { 46c36cf2e9Sopenharmony_ci this.unregisterCallback(); 47c36cf2e9Sopenharmony_ci this.printJobChangeListeners?.clear(); 48c36cf2e9Sopenharmony_ci } 49c36cf2e9Sopenharmony_ci 50c36cf2e9Sopenharmony_ci registerCallback(): void { 51c36cf2e9Sopenharmony_ci Log.info(TAG, `registerCallback isRegister:${this.isRegister}`); 52c36cf2e9Sopenharmony_ci if (!this.isRegister) { 53c36cf2e9Sopenharmony_ci print.on(`jobStateChange`, this.onJobStateChanged); 54c36cf2e9Sopenharmony_ci this.isRegister = true; 55c36cf2e9Sopenharmony_ci } 56c36cf2e9Sopenharmony_ci } 57c36cf2e9Sopenharmony_ci unregisterCallback(): void { 58c36cf2e9Sopenharmony_ci Log.info(TAG, `unregisterCallback isRegister:${this.isRegister}`); 59c36cf2e9Sopenharmony_ci if (this.isRegister) { 60c36cf2e9Sopenharmony_ci print.off('jobStateChange', (data: boolean) => { 61c36cf2e9Sopenharmony_ci Log.info(TAG, `off jobStateChange data:` + JSON.stringify(data)); 62c36cf2e9Sopenharmony_ci }); 63c36cf2e9Sopenharmony_ci this.isRegister = false; 64c36cf2e9Sopenharmony_ci } 65c36cf2e9Sopenharmony_ci } 66c36cf2e9Sopenharmony_ci 67c36cf2e9Sopenharmony_ci registerJobChangeListener(key: string, listener: PrintJobChangeListener): void { 68c36cf2e9Sopenharmony_ci Log.info(TAG, `registerJobChangeListener key:${key}`); 69c36cf2e9Sopenharmony_ci if (key === null || listener === null) { 70c36cf2e9Sopenharmony_ci return; 71c36cf2e9Sopenharmony_ci } 72c36cf2e9Sopenharmony_ci this.printJobChangeListeners?.set(key, listener); 73c36cf2e9Sopenharmony_ci } 74c36cf2e9Sopenharmony_ci 75c36cf2e9Sopenharmony_ci unregisterJobChangeListener(key: string): void { 76c36cf2e9Sopenharmony_ci if (key === null) { 77c36cf2e9Sopenharmony_ci return; 78c36cf2e9Sopenharmony_ci } 79c36cf2e9Sopenharmony_ci this.printJobChangeListeners?.delete(key); 80c36cf2e9Sopenharmony_ci } 81c36cf2e9Sopenharmony_ci 82c36cf2e9Sopenharmony_ci async getPrintJobQueue(printerId?: string): Promise<void> { 83c36cf2e9Sopenharmony_ci let remoteJobQueue: Array<PrintJob> = await Promise.resolve(queryAllPrintJobs(printerId)); 84c36cf2e9Sopenharmony_ci let sortedJobQueue: Array<PrintJob> = await Promise.resolve(this.sortPrintJobs(remoteJobQueue)); 85c36cf2e9Sopenharmony_ci await Promise.resolve(this.updateLocalPrintJobQueue(sortedJobQueue)); 86c36cf2e9Sopenharmony_ci } 87c36cf2e9Sopenharmony_ci 88c36cf2e9Sopenharmony_ci private updateLocalPrintJobQueue(remoteJobQueue?: Array<PrintJob>): void { 89c36cf2e9Sopenharmony_ci Log.info(TAG, `updateLocalPrintJobQueue remoteJobQueue.length:${remoteJobQueue.length},localJobMap.length: ${this.localJobMap.size}`) 90c36cf2e9Sopenharmony_ci if (remoteJobQueue.length === 0) { 91c36cf2e9Sopenharmony_ci this.localJobMap.clear(); 92c36cf2e9Sopenharmony_ci this.notifyAllPrintJobsFinished(); 93c36cf2e9Sopenharmony_ci Log.debug(TAG, 'updateLocalPrintJobQueue notifyAllPrintJobsFinished'); 94c36cf2e9Sopenharmony_ci } else { 95c36cf2e9Sopenharmony_ci for (let item of remoteJobQueue) { 96c36cf2e9Sopenharmony_ci this.localJobMap.set(item.jobId, item); 97c36cf2e9Sopenharmony_ci this.printJobChangeListeners?.forEach((listener, key) => { 98c36cf2e9Sopenharmony_ci Log.info(TAG, `updateLocalPrintJobQueue listener.onAddPrintJob:Key:${key}, jobId:${item.jobId}`); 99c36cf2e9Sopenharmony_ci listener?.onAddPrintJob(item, this.checkBlockInQueue()); 100c36cf2e9Sopenharmony_ci }); 101c36cf2e9Sopenharmony_ci } 102c36cf2e9Sopenharmony_ci } 103c36cf2e9Sopenharmony_ci } 104c36cf2e9Sopenharmony_ci 105c36cf2e9Sopenharmony_ci cancelPrintJob(jobId: string): void { 106c36cf2e9Sopenharmony_ci Log.info(TAG, 'cancelPrintJob enter.'); 107c36cf2e9Sopenharmony_ci let job = this.localJobMap.get(jobId); 108c36cf2e9Sopenharmony_ci if (job) { 109c36cf2e9Sopenharmony_ci Log.info(TAG, `cancelPrintJob jobId:${jobId}`); 110c36cf2e9Sopenharmony_ci print.cancelPrintJob(jobId).then((data)=> { 111c36cf2e9Sopenharmony_ci Log.info(TAG, 'cancelPrintJob success, data:' + JSON.stringify(data)); 112c36cf2e9Sopenharmony_ci }).catch((err) =>{ 113c36cf2e9Sopenharmony_ci Log.info(TAG, 'cancelPrintJob failed, err:' + JSON.stringify(err)); 114c36cf2e9Sopenharmony_ci }); 115c36cf2e9Sopenharmony_ci } 116c36cf2e9Sopenharmony_ci Log.info(TAG, 'cancelPrintJob end.'); 117c36cf2e9Sopenharmony_ci } 118c36cf2e9Sopenharmony_ci 119c36cf2e9Sopenharmony_ci updatePrintJob(job: PrintJob): void { 120c36cf2e9Sopenharmony_ci Log.info(TAG, 'updatePrintJob enter.'); 121c36cf2e9Sopenharmony_ci if (this.localJobMap.has(job.jobId)) { 122c36cf2e9Sopenharmony_ci Log.info(TAG, `updatePrintJob jobId: ${job.jobId}`); 123c36cf2e9Sopenharmony_ci this.localJobMap.set(job.jobId, job); 124c36cf2e9Sopenharmony_ci this.printJobChangeListeners?.forEach((listener, key) => { 125c36cf2e9Sopenharmony_ci Log.info(TAG, `updatePrintJob listener.onUpdatePrintJob: Key:${key}, jobState:${job.jobState}`); 126c36cf2e9Sopenharmony_ci listener?.onUpdatePrintJob(job, this.checkBlockInQueue()); 127c36cf2e9Sopenharmony_ci }); 128c36cf2e9Sopenharmony_ci this.handleCompleteJob(job); 129c36cf2e9Sopenharmony_ci } 130c36cf2e9Sopenharmony_ci Log.info(TAG, 'updatePrintJob end.'); 131c36cf2e9Sopenharmony_ci } 132c36cf2e9Sopenharmony_ci 133c36cf2e9Sopenharmony_ci handleCompleteJob(job: PrintJob): void { 134c36cf2e9Sopenharmony_ci Log.info(TAG, 'handleCompleteJob enter.'); 135c36cf2e9Sopenharmony_ci if (job.jobState == print.PrintJobState.PRINT_JOB_COMPLETED) { 136c36cf2e9Sopenharmony_ci setTimeout(() => { 137c36cf2e9Sopenharmony_ci Log.info(TAG, 'handleCompleteJob show completed job time out, jobId=' + job.jobId); 138c36cf2e9Sopenharmony_ci this.removePrintJob(job.jobId); 139c36cf2e9Sopenharmony_ci }, Constants.SHOW_JOB_COMPLETED_TIMEOUT); 140c36cf2e9Sopenharmony_ci } 141c36cf2e9Sopenharmony_ci Log.info(TAG, `handleCompleteJob end, jobId:${job.jobId}`); 142c36cf2e9Sopenharmony_ci } 143c36cf2e9Sopenharmony_ci 144c36cf2e9Sopenharmony_ci private removePrintJob(jobId: string): void { 145c36cf2e9Sopenharmony_ci Log.info(TAG, `removePrintJob enter, jobId:${jobId}`); 146c36cf2e9Sopenharmony_ci if (this.localJobMap.delete(jobId)) { 147c36cf2e9Sopenharmony_ci Log.info(TAG, `removePrintJob jobId:${jobId} success.`); 148c36cf2e9Sopenharmony_ci this.printJobChangeListeners?.forEach((listener, key) => { 149c36cf2e9Sopenharmony_ci Log.info(TAG, `removePrintJob listener.onRemovePrintJob: Key:${key}, jobId:${jobId}`); 150c36cf2e9Sopenharmony_ci listener?.onRemovePrintJob(jobId, this.checkBlockInQueue()); 151c36cf2e9Sopenharmony_ci }); 152c36cf2e9Sopenharmony_ci } 153c36cf2e9Sopenharmony_ci 154c36cf2e9Sopenharmony_ci if (this.localJobMap.size === 0) { 155c36cf2e9Sopenharmony_ci Log.debug(TAG, 'removePrintJob notifyAllPrintJobsFinished.'); 156c36cf2e9Sopenharmony_ci this.notifyAllPrintJobsFinished(); 157c36cf2e9Sopenharmony_ci } 158c36cf2e9Sopenharmony_ci Log.info(TAG, `removePrintJob end.`); 159c36cf2e9Sopenharmony_ci } 160c36cf2e9Sopenharmony_ci 161c36cf2e9Sopenharmony_ci private deleteLocalSource(job: PrintJob): Promise<void> { 162c36cf2e9Sopenharmony_ci if (CheckEmptyUtils.isEmpty(job)) { 163c36cf2e9Sopenharmony_ci Log.warn(TAG, 'deleteLocalSource invalid job.'); 164c36cf2e9Sopenharmony_ci return; 165c36cf2e9Sopenharmony_ci } 166c36cf2e9Sopenharmony_ci if (job.jobState === print.PrintJobState.PRINT_JOB_BLOCKED || job.jobState === print.PrintJobState.PRINT_JOB_COMPLETED) { 167c36cf2e9Sopenharmony_ci Log.info(TAG, `deleteLocalSource jobId:${job.jobId}`); 168c36cf2e9Sopenharmony_ci FileUtil.deleteSource(job.jobFiles); 169c36cf2e9Sopenharmony_ci } 170c36cf2e9Sopenharmony_ci Log.info(TAG, 'deleteLocalSource end.'); 171c36cf2e9Sopenharmony_ci } 172c36cf2e9Sopenharmony_ci 173c36cf2e9Sopenharmony_ci checkBlockInQueue(): number { 174c36cf2e9Sopenharmony_ci for(let value of this.localJobMap.values()) { 175c36cf2e9Sopenharmony_ci if (value.jobState === print.PrintJobState.PRINT_JOB_BLOCKED) { 176c36cf2e9Sopenharmony_ci return value.jobSubstate; 177c36cf2e9Sopenharmony_ci } 178c36cf2e9Sopenharmony_ci } 179c36cf2e9Sopenharmony_ci return Constants.NEGATIVE_1; 180c36cf2e9Sopenharmony_ci } 181c36cf2e9Sopenharmony_ci 182c36cf2e9Sopenharmony_ci private sortPrintJobs(jobArray: Array<PrintJob>): Promise<Array<PrintJob>> { 183c36cf2e9Sopenharmony_ci return new Promise((resolve) => { 184c36cf2e9Sopenharmony_ci jobArray.sort((job1, job2): number => { 185c36cf2e9Sopenharmony_ci return Number(job1.jobId) - Number(job2.jobId); 186c36cf2e9Sopenharmony_ci }); 187c36cf2e9Sopenharmony_ci resolve(jobArray); 188c36cf2e9Sopenharmony_ci }); 189c36cf2e9Sopenharmony_ci } 190c36cf2e9Sopenharmony_ci 191c36cf2e9Sopenharmony_ci private notifyAllPrintJobsFinished(): void { 192c36cf2e9Sopenharmony_ci Log.info(TAG, 'notifyAllPrintJobsFinished enter.'); 193c36cf2e9Sopenharmony_ci this.printJobChangeListeners?.forEach((listener, key) => { 194c36cf2e9Sopenharmony_ci Log.info(TAG, 'notifyAllPrintJobsFinished listener.onAllPrintJobsFinished.'); 195c36cf2e9Sopenharmony_ci listener?.onAllPrintJobsFinished(); 196c36cf2e9Sopenharmony_ci }); 197c36cf2e9Sopenharmony_ci Log.info(TAG, 'notifyAllPrintJobsFinished end.'); 198c36cf2e9Sopenharmony_ci } 199c36cf2e9Sopenharmony_ci} 200c36cf2e9Sopenharmony_ciexport let printJobMgr = SingletonHelper.getInstance(PrintJobManager, TAG);