• 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 '@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}