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 '@ohos.print'; 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.delayTimer !== undefined) { 99 clearTimeout(this.delayTimer); 100 } 101 Log.debug(TAG, 'stop connect to: ' + CommonUtils.getSecurityMac(this.mPrinter.getDeviceAddress())); 102 this.mWifiModel.stopConnection(); 103 } 104 105 /** 106 * 取消连接的状态回调 107 * 108 * @param p2pLinkedInfo 109 */ 110 private handleP2pCancelConnectChange = (p2pLinkedInfo: wifi.WifiP2pLinkedInfo): void => { 111 if (this.connectState === P2PPrinterConnection.connectStateInit) { 112 Log.debug(TAG, 'cancel connect msg has report, ignore'); 113 return; 114 } 115 Log.error(TAG, `p2p printer cancel Connect Change enter, state: ${p2pLinkedInfo.connectState}`); 116 if (p2pLinkedInfo.connectState === wifi.P2pConnectState.DISCONNECTED) { 117 Log.error(TAG, 'cancel connect success'); 118 this.connectState = P2PPrinterConnection.connectStateInit; 119 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pConnectionChange, this.handleP2pCancelConnectChange); 120 this.connectToPrinter(); 121 } else { 122 Log.error(TAG, 'p2pConnectState is not false'); 123 } 124 }; 125 126 /** 127 * 连接的状态回调 128 * 129 * @param p2pLinkedInfo 130 */ 131 private p2pConnectionChangeReceive = (p2pLinkedInfo: wifi.WifiP2pLinkedInfo): void => { 132 if (this.connectState === P2PPrinterConnection.connectStaConnected) { 133 Log.debug(TAG, 'connect msg has report, ignore'); 134 return; 135 } 136 Log.error(TAG, 'p2p printer Connect state change: ' + p2pLinkedInfo.connectState + ', ip: ' + CommonUtils.getSecurityIp(<string>p2pLinkedInfo.groupOwnerAddr)); 137 if (p2pLinkedInfo.connectState === wifi.P2pConnectState.CONNECTED) { 138 // 连接成功, 清除邀请弹窗的的定时器 139 if (this.inviteDelayTimer !== undefined) { 140 clearTimeout(this.inviteDelayTimer); 141 } 142 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pPeerDeviceChange); 143 if (p2pLinkedInfo.groupOwnerAddr.length === 0) { 144 Log.error(TAG, 'p2pConnectState is true, groupOwnerAddr is null'); 145 } else { 146 this.connectState = P2PPrinterConnection.connectStaConnected; 147 // 获取打印机ip成功, 清除连接失败的定时器 148 if (this.delayTimer !== undefined) { 149 clearTimeout(this.delayTimer); 150 } 151 let printerIp: string = <string>p2pLinkedInfo.groupOwnerAddr; 152 Log.info(TAG, 'printer is ' + CommonUtils.getSecurityIp(printerIp)); 153 this.mPrinter.setUri(printerIp); 154 // 取消连接状态变化的监听事件 155 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pConnectionChange, this.p2pConnectionChangeReceive); 156 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pPeerDeviceChange, this.p2pPeersChangeReceive); 157 this.mWifiModel.removeListener(this); 158 // 通知连接成功 159 this.mListener.onConnectionComplete(this.mPrinter); 160 } 161 } else { 162 Log.error(TAG, 'p2pConnectState is false'); 163 } 164 }; 165 166 private p2pPeersChangeReceive = (p2pDevicesLists: wifi.WifiP2pDevice[]): void => { 167 Log.debug(TAG, 'p2pPeersChangeReceive, device len: ' + p2pDevicesLists.length); 168 if (CheckEmptyUtils.isEmptyArr<wifi.WifiP2pDevice>(p2pDevicesLists)) { 169 Log.error(TAG, 'p2pDevicesLists is empty'); 170 return; 171 } 172 let device = p2pDevicesLists.find((p2pDevice) => { 173 return p2pDevice.deviceAddress === this.mPrinter.getDeviceAddress(); 174 }); 175 if (CheckEmptyUtils.isEmpty(device)) { 176 return; 177 } 178 // @ts-ignore 179 if (!this.invited && device.devStatus === wifi.P2pDeviceStatus.INVITED) { 180 this.invited = true; 181 this.inviteDelayTimer = setTimeout(() => { 182 Log.info(TAG, 'printer is invite, notify the user'); 183 print.updateExtensionInfo(JSON.stringify(CONNECTION_POP)); 184 }, P2P_CONNECT_DELAYED_PERIOD); 185 } 186 }; 187 188 private discoveryPrinterCallback = (p2pDevices: wifi.WifiP2pDevice[]): void => { 189 let device = p2pDevices.find((device: wifi.WifiP2pDevice) => { 190 return device.deviceAddress === this.mPrinter.getDeviceAddress(); 191 }); 192 if (CheckEmptyUtils.isEmpty(device)) { 193 return; 194 } 195 // 打印机存在,执行连接 196 Log.info(TAG, 'printer is found'); 197 if (this.connectState === P2PPrinterConnection.connectStateDiscovery) { 198 Log.info(TAG, 'printer has found, ignore'); 199 return; 200 } 201 this.connectState = P2PPrinterConnection.connectStateDiscovery; 202 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pPeerDeviceChange, this.discoveryPrinterCallback); 203 this.startConnect(this.mPrinter); 204 }; 205 206 /** 207 * 开始连接打印机 208 * 209 * @param printer 210 */ 211 private connectToPrinter(): void { 212 Log.info(TAG, 'start find printer'); 213 this.delayTimer = setTimeout(this.connectTimeOutOperation, CONNECT_DELAYED_TIME); 214 // 发现打印机 215 this.mWifiModel.registerWifiP2pEvent(WifiModel.p2pPeerDeviceChange, this.discoveryPrinterCallback); 216 this.mWifiModel.discoveryP2pDevices(); 217 this.mWifiModel.getP2pDevices(this.discoveryPrinterCallback); 218 } 219 220 /** 221 * 30s后连接超时,清除资源 222 */ 223 private connectTimeOutOperation = (): void => { 224 this.mWifiModel.removeListener(this); 225 if (this.connectState === P2PPrinterConnection.connectStaConnected) { 226 Log.error(TAG, 'printer is connected, timer close fail'); 227 } else if (this.connectState === P2PPrinterConnection.connectStateInit) { 228 // 打印机未发现 229 Log.error(TAG, 'discovery delayed, printer is not found'); 230 this.mWifiModel.removeListener(this); 231 this.mListener.onConnectionDelayed(); 232 } else { 233 // 连接超时 234 Log.error(TAG, 'connection delayed'); 235 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pConnectionChange, this.p2pConnectionChangeReceive); 236 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pPeerDeviceChange, this.p2pPeersChangeReceive); 237 this.mWifiModel.removeListener(this); 238 this.mWifiModel.stopConnection(); 239 this.mListener.onConnectionDelayed(); 240 } 241 }; 242 243 private startConnect(printer: DiscoveredPrinter): void { 244 Log.debug(TAG, 'connect to ' + CommonUtils.getSecurityMac(printer.getDeviceAddress())); 245 let config: wifi.WifiP2PConfig = this.configForPeer(printer); 246 this.mWifiModel.registerWifiP2pEvent(WifiModel.p2pConnectionChange, this.p2pConnectionChangeReceive); 247 this.mWifiModel.registerWifiP2pEvent(WifiModel.p2pPeerDeviceChange, this.p2pPeersChangeReceive); 248 let connectionOperation: boolean = this.mWifiModel.connectToPrinter(config); 249 if (!connectionOperation) { 250 Log.error(TAG, 'connection operation failed'); 251 if (this.delayTimer !== undefined) { 252 clearTimeout(this.delayTimer); 253 } 254 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pConnectionChange, this.p2pConnectionChangeReceive); 255 this.mWifiModel.unregisterWifiP2pEvent(WifiModel.p2pPeerDeviceChange, this.p2pPeersChangeReceive); 256 this.mListener.onConnectionDelayed(); 257 return; 258 } 259 Log.error(TAG, 'connection operation success'); 260 } 261 262 /** 263 * 获取连接设置项 264 * @param printer 265 */ 266 private configForPeer(printer: DiscoveredPrinter): wifi.WifiP2PConfig { 267 return { 268 deviceAddress: printer.getDeviceAddress(), 269 netId: NetId.TEMPORARY_GROUP, 270 passphrase: '', 271 groupName: '', 272 goBand: wifi.GroupOwnerBand.GO_BAND_AUTO, 273 }; 274 } 275 276 onConnectionStateChanged(data): void { 277 if (data.event === CommonEventManager.Support.COMMON_EVENT_WIFI_POWER_STATE && data.code === WIFI_POWER_CLOSED) { 278 // 上报wifi关闭事件 279 Log.error(TAG, 'wifi state is closed, eventData: ' + JSON.stringify(data)); 280 if (this.connectState === P2PPrinterConnection.connectStateDiscovery) { 281 Log.info(TAG, 'p2p is connecting'); 282 this.mListener.onConnectionComplete(null); 283 this.close(); 284 } 285 } 286 } 287} 288 289enum NetId { 290 TEMPORARY_GROUP = -1, 291 PERMANENT_GROUP = -2 292}