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, 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'; 26import { print } from '@kit.BasicServicesKit'; 27 28const TAG = 'LocalPrinter'; 29 30export default class LocalPrinter implements ConnectionListener, OnLocalPrinterCapabilities { 31 private static readonly p2pDiscoveryProtocol: string = 'wifi_direct'; 32 private static readonly descriptionSplit: string = '&&'; 33 private static readonly maxRetryTimes: number = 2; 34 private readonly mPrintServiceAdapter: PrintServiceAdapter; 35 private readonly mSession: LocalDiscoverySession; 36 private readonly mPrinterId: string; // number类型 37 38 private mTracking: boolean = false; //是否正在执行连接 39 private mCapabilities: PrinterCapability; 40 private mDiscoveredPrinter: DiscoveredPrinter; 41 private mP2pPrinterConnection: P2PPrinterConnection; 42 private getCapsFailedTimes: number = 0; 43 44 constructor(printServiceAdapter: PrintServiceAdapter, session: LocalDiscoverySession, 45 discoveredPrinter: DiscoveredPrinter) { 46 this.mPrintServiceAdapter = printServiceAdapter; 47 this.mSession = session; 48 this.mDiscoveredPrinter = discoveredPrinter; 49 this.mPrinterId = discoveredPrinter.getId(); 50 } 51 52 /** 53 * get capabilities 54 * 55 * @return Return capabilities or null if not present 56 */ 57 getCapabilities(): void { 58 if (CheckEmptyUtils.isEmpty(this.mDiscoveredPrinter)) { 59 Log.error(TAG, 'discovery printer is undefined'); 60 return; 61 } 62 Log.info(TAG, 'caps is empty, now to request'); 63 let capabilitiesCache: CapabilitiesCache = this.mPrintServiceAdapter.capabilitiesCache; 64 capabilitiesCache.requestCapabilities(this.mDiscoveredPrinter, this); 65 } 66 67 /** 68 * Create a PrinterInfo from this record or null if not possible 69 * 70 * @param knownGood boolean 71 * @return PrinterInfo or null 72 */ 73 createPrinterInfo(): PrinterInfo { 74 //创建PrinterInfo对象 返回给打印框架 75 let printerInfo: PrinterInfo = new PrinterInfo(this.mPrinterId, this.mDiscoveredPrinter.getDeviceName(), print.PrinterState.PRINTER_ADDED); 76 if (!CheckEmptyUtils.isEmpty(this.mCapabilities)) { 77 let printerCapability: PrinterCapability = new PrinterCapability(); 78 LocalPrinterCapabilities.buildPrinterCapability(printerCapability, this.mCapabilities); 79 printerInfo.capability = printerCapability; 80 printerInfo.description = LocalPrinter.p2pDiscoveryProtocol + 81 LocalPrinter.descriptionSplit + 82 this.mDiscoveredPrinter.getUri().host; 83 let options: string = LocalPrinterCapabilities.buildExtraCaps(this.mCapabilities, this.mDiscoveredPrinter.getUri().toString()); 84 printerInfo.options = options; 85 } 86 return printerInfo; 87 } 88 89 90 /** 91 * 开始连接打印机 92 */ 93 public startTracking(): void { 94 Log.debug(TAG, 'start connect to printer, track is: ' + this.mTracking); 95 if (!P2PUtils.isP2p(this.mDiscoveredPrinter)) { 96 Log.debug(TAG, 'mdns printer'); 97 this.getCapabilities(); 98 return; 99 } 100 if (this.mTracking) { 101 Log.error(TAG, 'ERROR: isTracking: ' + this.mTracking); 102 return; 103 } 104 this.mTracking = true; 105 Log.debug(TAG, 'p2p printer'); 106 if (!CheckEmptyUtils.isEmpty(this.mP2pPrinterConnection)) { 107 Log.error(TAG, 'ERROR: connection in progress'); 108 this.mP2pPrinterConnection = undefined; 109 return; 110 } 111 this.mSession.addConnectingId(<string> this.mDiscoveredPrinter.getId()); 112 this.mP2pPrinterConnection = new P2PPrinterConnection(this.mPrintServiceAdapter, this.mDiscoveredPrinter, this); 113 this.mP2pPrinterConnection.connectToPeer(); 114 } 115 116 /** 117 * 停止连接打印机 118 */ 119 public stopTracking(): void { 120 if (!P2PUtils.isP2p(this.mDiscoveredPrinter)) { 121 Log.debug(TAG, 'mdns printer, no need stop tracking'); 122 return; 123 } 124 if (this.mP2pPrinterConnection !== undefined) { 125 Log.info(TAG, 'printer is connecting, close'); 126 this.mSession.removeConnectedId(this.mPrinterId); 127 this.mP2pPrinterConnection.close(); 128 } else { 129 Log.info(TAG, 'mP2pPrinterConnection is undefined, remove p2p group'); 130 this.mPrintServiceAdapter.wifiModel.getP2pLinkInfo().then((linkInfo: wifi.WifiP2pLinkedInfo) => { 131 if (linkInfo.connectState === wifi.P2pConnectState.CONNECTED) { 132 this.mPrintServiceAdapter.wifiModel.disconnectToPrinter(); 133 } else { 134 Log.info(TAG, 'p2p is not connected'); 135 this.mPrintServiceAdapter.wifiModel.stopConnection(); 136 } 137 }); 138 } 139 this.mP2pPrinterConnection = undefined; 140 this.mTracking = false; 141 } 142 143 /** 144 * get printerId 145 * 146 * @return PrinterId 147 */ 148 public getPrinterId(): string { 149 return this.mPrinterId; 150 } 151 152 public setDiscoveryPrinter(printer: DiscoveredPrinter): void { 153 this.mDiscoveredPrinter = printer; 154 } 155 156 public getDiscoveryPrinter(): DiscoveredPrinter { 157 Log.debug(TAG, 'getDiscoveryPrinter: ' + this.mDiscoveredPrinter.toString()); 158 return this.mDiscoveredPrinter; 159 } 160 161 162 /** 163 * 获取打印机能力成功的回调 164 * 165 * @param printerCaps 166 */ 167 onCapabilities(printerCaps: PrinterCapability): void { 168 if (!CheckEmptyUtils.isEmpty(printerCaps)) { 169 this.mCapabilities = printerCaps; 170 this.getCapsFailedTimes = 0; 171 // 上报打印机获取能力成功的回调 172 let printerInfo: PrinterInfo = this.createPrinterInfo(); 173 print.updatePrinters([printerInfo]).catch((error) => { 174 Log.error(TAG, 'update error: ' + JSON.stringify(error)); 175 }); 176 } else { 177 if (this.getCapsFailedTimes < LocalPrinter.maxRetryTimes) { 178 Log.error(TAG, `getCapabilities failed, retry ${this.getCapsFailedTimes} times`); 179 this.getCapsFailedTimes++; 180 this.getCapabilities(); 181 } else { 182 Log.error(TAG, 'printerCaps is null'); 183 this.getCapsFailedTimes = 0; 184 print.updateExtensionInfo(JSON.stringify(IPP_CONNECT_ERROR)); 185 } 186 } 187 } 188 189 190 /** 191 * 打印机连接成功回调 192 * @param printer 193 */ 194 onConnectionComplete(printer: DiscoveredPrinter): void { 195 this.mTracking = false; 196 this.mP2pPrinterConnection = undefined; 197 if (CheckEmptyUtils.isEmpty(printer)) { 198 Log.error(TAG, 'connect failed'); 199 return; 200 } 201 this.mDiscoveredPrinter = printer; 202 this.mSession.updateLocalPrinter(printer); 203 // 上报打印机机连接成功的状态 204 // @ts-ignore 205 print.updatePrinterState(this.mPrinterId, PrinterState.PRINTER_CONNECTED); 206 this.mSession.removeConnectedId(this.mPrinterId); 207 208 //连接成功获取打印机能力 209 if (CheckEmptyUtils.isEmpty(this.mCapabilities)) { 210 this.getCapabilities(); 211 } else { 212 this.onCapabilities(this.mCapabilities); 213 } 214 } 215 216 /** 217 * 打印机连接超时回调 218 * @param delayed 219 */ 220 onConnectionDelayed(): void { 221 this.mTracking = false; 222 this.mP2pPrinterConnection = undefined; 223 // 通知打印框架连接失败 224 Log.error(TAG, 'connect delay'); 225 print.updatePrinterState(this.mPrinterId, print.PrinterState.PRINTER_DISCONNECTED); 226 this.mSession.removeConnectedId(this.mPrinterId); 227 } 228}