• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}