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_POWER_CLOSED } from '@ohos/common'; 17import { CONNECTION_POP } from '@ohos/common'; 18import type DiscoveredPrinter from '../discovery/DiscoveredPrinter'; 19import type { PrintServiceAdapter } from '../PrintServiceAdapter'; 20import type ConnectionListener from '../connect/ConnectionListener'; 21import { Log } from '@ohos/common'; 22import { WifiModel } from '../model/WifiModel'; 23import wifi from '@ohos.wifi'; 24import CheckEmptyUtils from '@ohos/common'; 25import CommonUtils from '../utils/CommonUtils'; 26import type { WifiListener } from '../model/WifiModel'; 27import CommonEventManager from '@ohos.commonEventManager'; 28// @ts-ignore 29import { print } from '@kit.BasicServicesKit'; 30 31const TAG: string = 'P2PPrinterConnection'; 32const CONNECT_DELAYED_TIME: number = 30000; 33const P2P_CONNECT_DELAYED_PERIOD: number = 3000; 34 35export default class P2PPrinterConnection implements WifiListener { 36 37 private static readonly connectStateInit: number = 1; 38 private static readonly connectStateDiscovery: number = 2; 39 private static readonly connectStaConnected: number = 3; 40 41 private readonly mPrintServiceAdapter: PrintServiceAdapter; 42 private readonly mPrinter: DiscoveredPrinter; 43 private mListener: ConnectionListener; 44 private connectState: number; 45 private mWifiModel: WifiModel; 46 private delayTimer: number; 47 private invited: boolean = false; 48 private inviteDelayTimer: number; 49 50 constructor(printServiceAdapter: PrintServiceAdapter, printer: DiscoveredPrinter, listener: ConnectionListener) { 51 this.mPrintServiceAdapter = printServiceAdapter; 52 this.mWifiModel = this.mPrintServiceAdapter.wifiModel; 53 this.mListener = listener; 54 this.mPrinter = printer; 55 this.mWifiModel.addListener(this); 56 } 57 58 /** 59 * 连接打印机 60 * 61 * @param p2pLinkInfo 连接信息 62 */ 63 public connectToPeer(): void { 64 Log.info(TAG, 'connectToPeer enter, state: ' + this.connectState); 65 this.mWifiModel.getP2pLinkInfo().then((p2pLinkInfo: wifi.WifiP2pLinkedInfo) => { 66 if (p2pLinkInfo.connectState === wifi.P2pConnectState.CONNECTED) { 67 //当前状态已连接 68 Log.info(TAG, 'client state is connecting'); 69 wifi.getCurrentGroup().then((groupInfo: wifi.WifiP2pGroupInfo) => { 70 Log.info(TAG, 'get group info success'); 71 if (groupInfo.ownerInfo.deviceAddress === this.mPrinter.getDeviceAddress()) { 72 //当前打印机已经处在连接状态 73 Log.info(TAG, 'The printer is already connected.'); 74 this.mPrinter.setUri(<string>groupInfo.goIpAddress); 75 this.mListener.onConnectionComplete(this.mPrinter); 76 } else { 77 //当前状态已连接, 断开连接, 连接其它打印机 78 Log.info(TAG, 'connect to other printers'); 79 this.mWifiModel.registerWifiP2pEvent(WifiModel.p2pConnectionChange, this.handleP2pCancelConnectChange); 80 this.mWifiModel.disconnectToPrinter(); 81 } 82 }).catch((error) => { 83 Log.error(TAG, 'getCurrentGroup error: ' + JSON.stringify(error)); 84 }); 85 } else if (p2pLinkInfo.connectState === wifi.P2pConnectState.DISCONNECTED) { 86 //当前状态未连接 87 Log.info(TAG, 'client state is not connecting, start to connect'); 88 this.connectToPrinter(); 89 } else { 90 Log.error(TAG, 'unknown error'); 91 } 92 }).catch((error) => { 93 Log.error(TAG, 'getP2pLinkInfo error: ' + JSON.stringify(error)); 94 }); 95 } 96 97 public close(): void { 98 if (this.inviteDelayTimer !== undefined) { 99 clearTimeout(this.inviteDelayTimer); 100 } 101 if (this.delayTimer !== undefined) { 102 clearTimeout(this.delayTimer); 103 } 104 Log.debug(TAG, 'stop connect to: ' + CommonUtils.getSecurityMac(this.mPrinter.getDeviceAddress())); 105 this.mWifiModel.stopConnection(); 106 } 107 108 /** 109 * 取消连接的状态回调 110 * 111 * @param p2pLinkedInfo 112 */ 113 private handleP2pCancelConnectChange = (p2pLinkedInfo: wifi.WifiP2pLinkedInfo): void => { 114 if (this.connectState === P2PPrinterConnection.connectStateInit) { 115 Log.debug(TAG, 'cancel connect msg has report, ignore'); 116 return; 117 } 118 Log.error(TAG, `p2p printer cancel Connect Change enter, state: ${p2pLinkedInfo.connectState}`); 119 if (p2pLinkedInfo.connectState === wifi.P2pConnectState.DISCONNECTED) { 120 Log.error(TAG, 'cancel connect success'); 121 this.connectState = P2PPrinterConnection.connectStateInit; 122 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pConnectionChange, this.handleP2pCancelConnectChange); 123 this.connectToPrinter(); 124 } else { 125 Log.error(TAG, 'p2pConnectState is not false'); 126 } 127 }; 128 129 /** 130 * 连接的状态回调 131 * 132 * @param p2pLinkedInfo 133 */ 134 private p2pConnectionChangeReceive = (p2pLinkedInfo: wifi.WifiP2pLinkedInfo): void => { 135 if (this.connectState === P2PPrinterConnection.connectStaConnected) { 136 Log.debug(TAG, 'connect msg has report, ignore'); 137 return; 138 } 139 Log.error(TAG, 'p2p printer Connect state change: ' + p2pLinkedInfo.connectState + ', ip: ' + CommonUtils.getSecurityIp(<string>p2pLinkedInfo.groupOwnerAddr)); 140 if (p2pLinkedInfo.connectState === wifi.P2pConnectState.CONNECTED) { 141 // 连接成功, 清除邀请弹窗的的定时器 142 if (this.inviteDelayTimer !== undefined) { 143 clearTimeout(this.inviteDelayTimer); 144 } 145 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pPeerDeviceChange); 146 if (p2pLinkedInfo.groupOwnerAddr.length === 0) { 147 Log.error(TAG, 'p2pConnectState is true, groupOwnerAddr is null'); 148 } else { 149 this.connectState = P2PPrinterConnection.connectStaConnected; 150 // 获取打印机ip成功, 清除连接失败的定时器 151 if (this.delayTimer !== undefined) { 152 clearTimeout(this.delayTimer); 153 } 154 let printerIp: string = <string>p2pLinkedInfo.groupOwnerAddr; 155 Log.info(TAG, 'printer is ' + CommonUtils.getSecurityIp(printerIp)); 156 this.mPrinter.setUri(printerIp); 157 // 取消连接状态变化的监听事件 158 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pConnectionChange, this.p2pConnectionChangeReceive); 159 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pPeerDeviceChange, this.p2pPeersChangeReceive); 160 this.mWifiModel.removeListener(this); 161 // 通知连接成功 162 this.mListener.onConnectionComplete(this.mPrinter); 163 } 164 } else { 165 Log.error(TAG, 'p2pConnectState is false'); 166 } 167 }; 168 169 private p2pPeersChangeReceive = (p2pDevicesLists: wifi.WifiP2pDevice[]): void => { 170 Log.debug(TAG, 'p2pPeersChangeReceive, device len: ' + p2pDevicesLists.length); 171 if (CheckEmptyUtils.isEmptyArr<wifi.WifiP2pDevice>(p2pDevicesLists)) { 172 Log.error(TAG, 'p2pDevicesLists is empty'); 173 return; 174 } 175 let device = p2pDevicesLists.find((p2pDevice) => { 176 return p2pDevice.deviceAddress === this.mPrinter.getDeviceAddress(); 177 }); 178 if (CheckEmptyUtils.isEmpty(device)) { 179 return; 180 } 181 // @ts-ignore 182 if (!this.invited && device.devStatus === wifi.P2pDeviceStatus.INVITED) { 183 this.invited = true; 184 this.inviteDelayTimer = setTimeout(() => { 185 Log.info(TAG, 'printer is invite, notify the user'); 186 print.updateExtensionInfo(JSON.stringify(CONNECTION_POP)); 187 }, P2P_CONNECT_DELAYED_PERIOD); 188 } 189 }; 190 191 private discoveryPrinterCallback = (p2pDevices: wifi.WifiP2pDevice[]): void => { 192 let device = p2pDevices.find((device: wifi.WifiP2pDevice) => { 193 return device.deviceAddress === this.mPrinter.getDeviceAddress(); 194 }); 195 if (CheckEmptyUtils.isEmpty(device)) { 196 return; 197 } 198 // 打印机存在,执行连接 199 Log.info(TAG, 'printer is found'); 200 if (this.connectState === P2PPrinterConnection.connectStateDiscovery) { 201 Log.info(TAG, 'printer has found, ignore'); 202 return; 203 } 204 this.connectState = P2PPrinterConnection.connectStateDiscovery; 205 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pPeerDeviceChange, this.discoveryPrinterCallback); 206 this.startConnect(this.mPrinter); 207 }; 208 209 /** 210 * 开始连接打印机 211 * 212 * @param printer 213 */ 214 private connectToPrinter(): void { 215 Log.info(TAG, 'start find printer'); 216 this.delayTimer = setTimeout(this.connectTimeOutOperation, CONNECT_DELAYED_TIME); 217 // 发现打印机 218 this.mWifiModel.registerWifiP2pEvent(WifiModel.p2pPeerDeviceChange, this.discoveryPrinterCallback); 219 this.mWifiModel.discoveryP2pDevices(); 220 this.mWifiModel.getP2pDevices(this.discoveryPrinterCallback); 221 } 222 223 /** 224 * 30s后连接超时,清除资源 225 */ 226 private connectTimeOutOperation = (): void => { 227 this.mWifiModel.removeListener(this); 228 if (this.connectState === P2PPrinterConnection.connectStaConnected) { 229 Log.error(TAG, 'printer is connected, timer close fail'); 230 } else if (this.connectState === P2PPrinterConnection.connectStateInit) { 231 // 打印机未发现 232 Log.error(TAG, 'discovery delayed, printer is not found'); 233 this.mWifiModel.removeListener(this); 234 this.mListener.onConnectionDelayed(); 235 } else { 236 // 连接超时 237 Log.error(TAG, 'connection delayed'); 238 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pConnectionChange, this.p2pConnectionChangeReceive); 239 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pPeerDeviceChange, this.p2pPeersChangeReceive); 240 this.mWifiModel.removeListener(this); 241 this.mWifiModel.stopConnection(); 242 this.mListener.onConnectionDelayed(); 243 } 244 }; 245 246 private startConnect(printer: DiscoveredPrinter): void { 247 Log.debug(TAG, 'connect to ' + CommonUtils.getSecurityMac(printer.getDeviceAddress())); 248 let config: wifi.WifiP2PConfig = this.configForPeer(printer); 249 this.mWifiModel.registerWifiP2pEvent(WifiModel.p2pConnectionChange, this.p2pConnectionChangeReceive); 250 this.mWifiModel.registerWifiP2pEvent(WifiModel.p2pPeerDeviceChange, this.p2pPeersChangeReceive); 251 let connectionOperation: boolean = this.mWifiModel.connectToPrinter(config); 252 if (!connectionOperation) { 253 Log.error(TAG, 'connection operation failed'); 254 if (this.delayTimer !== undefined) { 255 clearTimeout(this.delayTimer); 256 } 257 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pConnectionChange, this.p2pConnectionChangeReceive); 258 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pPeerDeviceChange, this.p2pPeersChangeReceive); 259 this.mListener.onConnectionDelayed(); 260 return; 261 } 262 Log.error(TAG, 'connection operation success'); 263 } 264 265 /** 266 * 获取连接设置项 267 * @param printer 268 */ 269 private configForPeer(printer: DiscoveredPrinter): wifi.WifiP2PConfig { 270 return { 271 deviceAddress: printer.getDeviceAddress(), 272 netId: NetId.TEMPORARY_GROUP, 273 passphrase: '', 274 groupName: '', 275 goBand: wifi.GroupOwnerBand.GO_BAND_AUTO, 276 }; 277 } 278 279 onConnectionStateChanged(data): void { 280 if (data.event === CommonEventManager.Support.COMMON_EVENT_WIFI_POWER_STATE && data.code === WIFI_POWER_CLOSED) { 281 // 上报wifi关闭事件 282 Log.error(TAG, 'wifi state is closed, eventData: ' + JSON.stringify(data)); 283 if (this.connectState === P2PPrinterConnection.connectStateDiscovery) { 284 Log.info(TAG, 'p2p is connecting'); 285 this.mListener.onConnectionComplete(null); 286 this.close(); 287 } 288 } 289 } 290} 291 292enum NetId { 293 TEMPORARY_GROUP = -1, 294 PERMANENT_GROUP = -2 295}