• 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 { Log } from '@ohos/common';
17import CheckEmptyUtils from '@ohos/common';
18import CommonUtils from '../utils/CommonUtils';
19import type { WifiListener } from '../model/WifiModel';
20import ArrayList from '@ohos.util.ArrayList';
21import HashSet from '@ohos.util.HashSet';
22import wifi from '@ohos.wifi';
23import CommonEventManager from '@ohos.commonEventManager';
24
25const TAG = 'P2pDiscoveryChannel';
26const DISCOVERY_SLEEP: number = 60000;
27
28export class P2PDiscoveryChannel implements WifiListener {
29  private static instance: P2PDiscoveryChannel;
30  private static readonly printerPattern: RegExp = /^(^3-.+-[145])|(0003.+000[145])$/;
31  private readonly p2pDevices: ArrayList<wifi.WifiP2pDevice> = new ArrayList<wifi.WifiP2pDevice>();
32  private discoveryCallback: (found: boolean, peer: wifi.WifiP2pDevice) => void;
33  private discoverySleepTimer: number;
34  private wifiSubscriber;
35
36  public static getInstance(): P2PDiscoveryChannel {
37    Log.info(TAG, 'getInstance enter');
38    if (this.instance === undefined) {
39      this.instance = new P2PDiscoveryChannel();
40    }
41    return this.instance;
42  }
43
44  startDiscovery(callback: (found: boolean, peer: wifi.WifiP2pDevice) => void): void {
45    this.discoveryCallback = callback;
46    wifi.on('p2pPeerDeviceChange', this.updatePeerDevices);
47    this.startP2pDiscovery();
48    this.registerWifiCommonEvent();
49
50    // 3分钟后,native p2pService进入休眠状态,清除标记
51    this.discoverySleepTimer = setInterval(()=> {
52      Log.debug(TAG, 'native p2p service is sleep, start discovery');
53      this.startP2pDiscovery();
54    }, DISCOVERY_SLEEP);
55  }
56
57  private startP2pDiscovery(): void {
58    wifi.startDiscoverDevices();
59    wifi.getP2pPeerDevices().then((peers: wifi.WifiP2pDevice[]) => {
60      this.updatePeerDevices(peers);
61    });
62  }
63
64  /**
65   *  register wifi common event;
66   */
67  private async registerWifiCommonEvent(): Promise<void> {
68    try {
69      this.wifiSubscriber = await CommonEventManager.createSubscriber({events:
70      [CommonEventManager.Support.COMMON_EVENT_WIFI_P2P_CONN_STATE]});
71      CommonEventManager.subscribe(this.wifiSubscriber, (err, data) => {
72        if (err) {
73          Log.error(TAG, `subscribe failed, code is ${err.code}, message is ${err.message}`);
74        } else {
75          this.onConnectionStateChanged(data);
76        }
77      });
78    } catch (error) {
79      Log.error(TAG, 'create subscriber fail: ' + JSON.stringify(error));
80    }
81  }
82
83  private updatePeerDevices = (newDevices: wifi.WifiP2pDevice[]): void => {
84    if (CheckEmptyUtils.isEmptyArr<wifi.WifiP2pDevice>(newDevices)) {
85      Log.error(TAG, 'newDevices is empty');
86      return;
87    }
88    Log.debug(TAG, `found length: ${newDevices.length}`);
89    let oldDevices = new ArrayList<wifi.WifiP2pDevice>();
90    for (let p2pDevice of this.p2pDevices) {
91      oldDevices.add(p2pDevice);
92    }
93    this.p2pDevices.clear();
94    for (let newDevice of newDevices) {
95      if (newDevice !== undefined && newDevice.primaryDeviceType !== undefined &&
96      P2PDiscoveryChannel.printerPattern.test(<string>newDevice.primaryDeviceType)) {
97        let index = this.p2pDevices.convertToArray().findIndex((device) => {
98          return device.deviceAddress === newDevice.deviceAddress;
99        });
100        if (index < 0) {
101          this.p2pDevices.add(newDevice);
102        }
103      }
104    }
105
106    // notify new found devices
107    let foundAddress: HashSet<string> = new HashSet<string>();
108    let foundPrinters = this.p2pDevices.convertToArray().filter((newDevice) => {
109      foundAddress.add(newDevice.deviceAddress);
110      let index = oldDevices.convertToArray().findIndex((device) => {
111        return device.deviceAddress === newDevice.deviceAddress;
112      });
113      if (index < 0) {
114        return true;
115      }
116      return false;
117    });
118    if (!CheckEmptyUtils.isEmptyArr<wifi.WifiP2pDevice>(foundPrinters)) {
119      for (let foundPrinter of foundPrinters) {
120        this.discoveryCallback(true, foundPrinter);
121      }
122    }
123
124    // notify lost devices
125    for (let oldDevice of oldDevices) {
126      if (!foundAddress.has(oldDevice.deviceAddress)) {
127        this.discoveryCallback(false, oldDevice);
128      }
129    }
130  };
131
132  onConnectionStateChanged(data): void {
133    if (data.event === CommonEventManager.Support.COMMON_EVENT_WIFI_P2P_CONN_STATE && data.code === wifi.P2pConnectState.DISCONNECTED) {
134      Log.debug(TAG, 'p2p connect state change event: ' + JSON.stringify(data));
135      if (this.discoverySleepTimer !== undefined) {
136        this.startP2pDiscovery();
137      }
138    }
139  }
140
141  /**
142	 * stop discovery
143  */
144  public cancel(): void {
145    Log.info('stop p2p discovery');
146    this.p2pDevices.clear();
147    wifi.off('p2pPeerDeviceChange', this.updatePeerDevices);
148    wifi.stopDiscoverDevices();
149    if (this.wifiSubscriber !== undefined) {
150      CommonEventManager.unsubscribe(this.wifiSubscriber);
151    }
152    clearTimeout(this.discoverySleepTimer);
153  }
154}