1/* 2 * Copyright (c) 2023-2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import wifi from '@ohos.wifi'; 17import P2PUtils from './utils/P2pUtils'; 18import CheckEmptyUtils, { Log, PrinterCapability, PrinterInfo, PrinterState, IPP_CONNECT_ERROR } from '@ohos/common'; 19import type { PrintServiceAdapter } from './PrintServiceAdapter'; 20import type { LocalDiscoverySession } from './LocalDiscoverySession'; 21import type DiscoveredPrinter from './discovery/DiscoveredPrinter'; 22import LocalPrinterCapabilities from './napi/LocalPrinterCapabilities'; 23import type ConnectionListener from './connect/ConnectionListener'; 24import P2PPrinterConnection from './connect/P2pPrinterConnection'; 25import type { CapabilitiesCache, OnLocalPrinterCapabilities } from './ipp/CapabilitiesCache'; 26// @ts-ignore 27import print from '@ohos.print'; 28 29const TAG = 'LocalPrinter'; 30 31export default class LocalPrinter implements ConnectionListener, OnLocalPrinterCapabilities { 32 private static readonly p2pDiscoveryProtocol: string = 'wifi_direct'; 33 private static readonly descriptionSplit: string = '&&'; 34 private static readonly maxRetryTimes: number = 2; 35 private readonly mPrintServiceAdapter: PrintServiceAdapter; 36 private readonly mSession: LocalDiscoverySession; 37 private readonly mPrinterId: string; // number类型 38 39 private mTracking: boolean = false; //是否正在执行连接 40 private mCapabilities: PrinterCapability; 41 private mDiscoveredPrinter: DiscoveredPrinter; 42 private mP2pPrinterConnection: P2PPrinterConnection; 43 private getCapsFailedTimes: number = 0; 44 45 constructor(printServiceAdapter: PrintServiceAdapter, session: LocalDiscoverySession, 46 discoveredPrinter: DiscoveredPrinter) { 47 this.mPrintServiceAdapter = printServiceAdapter; 48 this.mSession = session; 49 this.mDiscoveredPrinter = discoveredPrinter; 50 this.mPrinterId = discoveredPrinter.getId(); 51 } 52 53 /** 54 * get capabilities 55 * 56 * @return Return capabilities or null if not present 57 */ 58 getCapabilities(): void { 59 if (CheckEmptyUtils.isEmpty(this.mDiscoveredPrinter)) { 60 Log.error(TAG, 'discovery printer is undefined'); 61 return; 62 } 63 Log.info(TAG, 'caps is empty, now to request'); 64 let capabilitiesCache: CapabilitiesCache = this.mPrintServiceAdapter.capabilitiesCache; 65 capabilitiesCache.requestCapabilities(this.mDiscoveredPrinter, this); 66 } 67 68 /** 69 * Create a PrinterInfo from this record or null if not possible 70 * 71 * @param knownGood boolean 72 * @return PrinterInfo or null 73 */ 74 createPrinterInfo(): PrinterInfo { 75 //创建PrinterInfo对象 返回给打印框架 76 let printerInfo: PrinterInfo = new PrinterInfo(); 77 printerInfo.printerId = this.mPrinterId; 78 printerInfo.printerName = this.mDiscoveredPrinter.getDeviceName(); 79 printerInfo.printerState = PrinterState.PRINTER_ADDED; 80 if (!CheckEmptyUtils.isEmpty(this.mCapabilities)) { 81 let printerCapability: PrinterCapability = new PrinterCapability(); 82 LocalPrinterCapabilities.buildPrinterCapability(printerCapability, this.mCapabilities); 83 printerInfo.capability = printerCapability; 84 printerInfo.description = LocalPrinter.p2pDiscoveryProtocol + 85 LocalPrinter.descriptionSplit + 86 this.mDiscoveredPrinter.getUri().host; 87 let options: string = LocalPrinterCapabilities.buildExtraCaps(this.mCapabilities, this.mDiscoveredPrinter.getUri().toString()); 88 printerInfo.option = options; 89 } 90 return printerInfo; 91 } 92 93 94 /** 95 * 开始连接打印机 96 */ 97 public startTracking(): void { 98 Log.debug(TAG, 'start connect to printer, track is: ' + this.mTracking); 99 if (!P2PUtils.isP2p(this.mDiscoveredPrinter)) { 100 Log.debug(TAG, 'mdns printer'); 101 this.getCapabilities(); 102 return; 103 } 104 if (this.mTracking) { 105 Log.error(TAG, 'ERROR: isTracking: ' + this.mTracking); 106 return; 107 } 108 this.mTracking = true; 109 Log.debug(TAG, 'p2p printer'); 110 if (!CheckEmptyUtils.isEmpty(this.mP2pPrinterConnection)) { 111 Log.error(TAG, 'ERROR: connection in progress'); 112 this.mP2pPrinterConnection = undefined; 113 return; 114 } 115 this.mSession.addConnectingId(<string> this.mDiscoveredPrinter.getId()); 116 this.mP2pPrinterConnection = new P2PPrinterConnection(this.mPrintServiceAdapter, this.mDiscoveredPrinter, this); 117 this.mP2pPrinterConnection.connectToPeer(); 118 } 119 120 /** 121 * 停止连接打印机 122 */ 123 public stopTracking(): void { 124 if (!P2PUtils.isP2p(this.mDiscoveredPrinter)) { 125 Log.debug(TAG, 'mdns printer, no need stop tracking'); 126 return; 127 } 128 if (this.mP2pPrinterConnection !== undefined) { 129 Log.info(TAG, 'printer is connecting, close'); 130 this.mSession.removeConnectedId(this.mPrinterId); 131 this.mP2pPrinterConnection.close(); 132 } else { 133 Log.info(TAG, 'mP2pPrinterConnection is undefined, remove p2p group'); 134 this.mPrintServiceAdapter.wifiModel.getP2pLinkInfo().then((linkInfo: wifi.WifiP2pLinkedInfo) => { 135 if (linkInfo.connectState === wifi.P2pConnectState.CONNECTED) { 136 this.mPrintServiceAdapter.wifiModel.disconnectToPrinter(); 137 } else { 138 Log.info(TAG, 'p2p is not connected'); 139 this.mPrintServiceAdapter.wifiModel.stopConnection(); 140 } 141 }); 142 } 143 this.mP2pPrinterConnection = undefined; 144 this.mTracking = false; 145 } 146 147 /** 148 * get printerId 149 * 150 * @return PrinterId 151 */ 152 public getPrinterId(): string { 153 return this.mPrinterId; 154 } 155 156 public setDiscoveryPrinter(printer: DiscoveredPrinter): void { 157 this.mDiscoveredPrinter = printer; 158 } 159 160 public getDiscoveryPrinter(): DiscoveredPrinter { 161 Log.debug(TAG, 'getDiscoveryPrinter: ' + this.mDiscoveredPrinter.toString()); 162 return this.mDiscoveredPrinter; 163 } 164 165 166 /** 167 * 获取打印机能力成功的回调 168 * 169 * @param printerCaps 170 */ 171 onCapabilities(printerCaps: PrinterCapability): void { 172 if (!CheckEmptyUtils.isEmpty(printerCaps)) { 173 this.mCapabilities = printerCaps; 174 this.getCapsFailedTimes = 0; 175 // 上报打印机获取能力成功的回调 176 let printerInfo: PrinterInfo = this.createPrinterInfo(); 177 print.updatePrinters([printerInfo]).then((result) => { 178 Log.info(TAG, 'update success result: ' + result); 179 }).catch((error) => { 180 Log.error(TAG, 'update error: ' + JSON.stringify(error)); 181 }); 182 } else { 183 if (this.getCapsFailedTimes < LocalPrinter.maxRetryTimes) { 184 Log.error(TAG, `getCapabilities failed, retry ${this.getCapsFailedTimes} times`); 185 this.getCapsFailedTimes++; 186 this.getCapabilities(); 187 } else { 188 Log.error(TAG, 'printerCaps is null'); 189 this.getCapsFailedTimes = 0; 190 print.updateExtensionInfo(JSON.stringify(IPP_CONNECT_ERROR)); 191 } 192 } 193 } 194 195 196 /** 197 * 打印机连接成功回调 198 * @param printer 199 */ 200 onConnectionComplete(printer: DiscoveredPrinter): void { 201 this.mTracking = false; 202 this.mP2pPrinterConnection = undefined; 203 if (CheckEmptyUtils.isEmpty(printer)) { 204 Log.error(TAG, 'connect failed'); 205 return; 206 } 207 this.mDiscoveredPrinter = printer; 208 this.mSession.updateLocalPrinter(printer); 209 // 上报打印机机连接成功的状态 210 // @ts-ignore 211 print.updatePrinterState(this.mPrinterId, PrinterState.PRINTER_CONNECTED); 212 this.mSession.removeConnectedId(this.mPrinterId); 213 214 //连接成功获取打印机能力 215 if (CheckEmptyUtils.isEmpty(this.mCapabilities)) { 216 this.getCapabilities(); 217 } else { 218 this.onCapabilities(this.mCapabilities); 219 } 220 } 221 222 /** 223 * 打印机连接超时回调 224 * @param delayed 225 */ 226 onConnectionDelayed(): void { 227 this.mTracking = false; 228 this.mP2pPrinterConnection = undefined; 229 // 通知打印框架连接失败 230 Log.error(TAG, 'connect delay'); 231 // @ts-ignore 232 print.updatePrinterState(this.mPrinterId, PrinterState.PRINTER_DISCONNECTED); 233 this.mSession.removeConnectedId(this.mPrinterId); 234 } 235}