• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/**
2 * Copyright (c) 2021 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 */
15import LogUtil from '../../../../../../../common/utils/src/main/ets/default/baseUtil/LogUtil';
16import ConfigData from '../../../../../../../common/utils/src/main/ets/default/baseUtil/ConfigData';
17import wifi from '@ohos.wifiManager';
18import BaseModel from '../../../../../../../common/utils/src/main/ets/default/model/BaseModel';
19import { BusinessError } from '@ohos.base';
20
21const MODULE_TAG = ConfigData.TAG + 'WifiModel -> ';
22const Undefined_TaskId = -1;
23export interface WifiScanInfo {
24  ssid: string,
25  bssid: string,
26  rssi: number,
27  band: number,
28  frequency: number,
29  timestamp: number,
30  securityType: number,
31};
32
33export enum ConnState {
34  /** The device is searching for an available AP. */
35  SCANNING,
36
37  /** The Wi-Fi connection is being set up. */
38  CONNECTING,
39
40  /** The Wi-Fi connection is being authenticated. */
41  AUTHENTICATING,
42
43  /** The IP address of the Wi-Fi connection is being obtained. */
44  OBTAINING_IPADDR,
45
46  /** The Wi-Fi connection has been set up. */
47  CONNECTED,
48
49  /** The Wi-Fi connection is being torn down. */
50  DISCONNECTING,
51
52  /** The Wi-Fi connection has been torn down. */
53  DISCONNECTED,
54
55  /** Failed to set up the Wi-Fi connection. */
56  UNKNOWN
57}
58
59export enum WiFiSummaryMap {
60  CONNECTED,
61  CONNECTING,
62  SAVE_ENCRYPTED,
63  SAVE_OPEN,
64  ENCRYPTED,
65  OPEN,
66  OBTAINING_IP,
67}
68
69export enum WiFiIntensityMap {
70  GOOD,
71  WELL,
72  NORMAL,
73  BAD,
74}
75
76export enum WiFiEncryptMethodMap {
77  OPEN,
78  WEP,
79  WPA,
80  WPA2,
81}
82
83export class ApScanResult {
84  // interface WifiScanInfo
85  private apInfo = {
86    ssid:'',
87    bssid: '',
88    rssi: -100,
89    band: 0,
90    frequency: 0,
91    timestamp: 0,
92    securityType: 1,
93  };
94  private connectStatus: number = ConnState.UNKNOWN;
95  private isSaved: boolean = false;
96
97  constructor(apInfo?: any);
98
99  constructor(apInfo: any) {
100    if (apInfo === null || apInfo === undefined) {
101      return;
102    }
103    this.apInfo = apInfo;
104  };
105
106  getApInfo() {
107    return this.apInfo;
108  }
109
110  getSignalLevel(): number {
111    return wifi.getSignalLevel(this.apInfo.rssi, this.apInfo.band);
112  }
113
114  isConnected(): boolean {
115    return (this.connectStatus === ConnState.CONNECTED);
116  }
117
118  isSavedConfig(): boolean {
119    return (this.isSaved === true);
120  }
121
122  isSecurityAp(): boolean {
123    // WiFiSecurityType is enum from 0 to 4, 0 is `Invalid`, 1 is `Open`, 2 to 4 is `Encrypted`
124    return (this.apInfo.securityType !== 1);
125  }
126
127  isValidAp(): boolean {
128    // no ssid or signal level 0 is invalid
129    return (this.apInfo.ssid !== '' && this.getSignalLevel() != 0);
130  }
131
132  updateConnectStatus(status: number) {
133    this.connectStatus = status;
134  }
135
136  updateSavedStatus(status: boolean) {
137    this.isSaved = status;
138  }
139
140  renderToListModel(): { settingIcon: string, settingSummary: number, settingTitle: string, settingValue: string,
141    settingArrow: string, settingArrowStyle: string, settingUri: string, apInfo: WifiScanInfo } {
142    function generateArrow(that: ApScanResult): string {
143      let signalLevel: string = that.getSignalLevel().toString();
144      let lockPrefix: string = 'lock_';
145      if (that.isSecurityAp() !== true) {
146        lockPrefix = '';
147      }
148      let result: string = `/res/image/ic_wifi_${lockPrefix}signal_${signalLevel}_dark.svg`;
149      return result;
150    }
151
152    function generateSummary(that: ApScanResult): number {
153      if (that.isConnected()) {
154        return WiFiSummaryMap.CONNECTED;
155      }
156      if (that.connectStatus === ConnState.CONNECTING) {
157        return WiFiSummaryMap.CONNECTING;
158      }
159      if (that.connectStatus === ConnState.OBTAINING_IPADDR) {
160        return WiFiSummaryMap.OBTAINING_IP;
161      }
162      if (that.isSavedConfig()) {
163        if (that.isSecurityAp()) {
164          return WiFiSummaryMap.SAVE_ENCRYPTED;
165        } else {
166          return WiFiSummaryMap.SAVE_OPEN;
167        }
168      } else {
169        if (that.isSecurityAp()) {
170          return WiFiSummaryMap.ENCRYPTED;
171        } else {
172          return WiFiSummaryMap.OPEN;
173        }
174      }
175    }
176
177    let ret = {
178      settingIcon: '',
179      settingSummary: generateSummary(this),
180      settingTitle: this.apInfo.ssid,
181      settingValue: '',
182      settingArrow: generateArrow(this),
183      settingArrowStyle: 'wifi',
184      settingUri: '',
185      apInfo: this.apInfo,
186    };
187    return ret;
188  }
189
190  toString(): string {
191    return `apInfo is: ssid=${this.getApInfo().ssid} signal=${this.getSignalLevel()} isConnected=${this.isConnected()}`;
192  }
193
194  static compare(x: ApScanResult, y: ApScanResult): number {
195    let xApInfo = x.getApInfo();
196    let yApInfo = y.getApInfo();
197    // rssi value is negative number
198    return ((-xApInfo.rssi) - (-yApInfo.rssi));
199  }
200
201  static filter(arr: ApScanResult[]): ApScanResult[] {
202    let hash = {};
203    return arr.reduce((total, currItem) => {
204      if (!hash[currItem.getApInfo().ssid]) {
205        hash[currItem.getApInfo().ssid] = true;
206        total.push(currItem);
207      }
208      return total;
209    }, []);
210  }
211
212  static index(arr: ApScanResult[], target: ApScanResult): number {
213    return arr.map((item) => {
214      return item.getApInfo().ssid;
215    }).indexOf(target.getApInfo().ssid);
216  }
217}
218
219export class WifiModel extends BaseModel {
220  private userSelectedAp: ApScanResult = new ApScanResult();
221  private linkedApInfo: wifi.WifiLinkedInfo = null
222  private scanTaskId: number = Undefined_TaskId;
223  private isScanning: boolean = false;
224
225  destroyWiFiModelData() {
226    this.linkedApInfo = undefined;
227    this.setUserSelectedAp(null);
228    AppStorage.SetOrCreate('slConnectedWifi', (new ApScanResult()).renderToListModel());
229  }
230
231  registerWiFiStatusObserver(callback) {
232    LogUtil.info(MODULE_TAG + 'start register wifi status observer');
233    wifi.on('wifiStateChange', callback);
234  }
235
236  unregisterWiFiStatusObserver() {
237    LogUtil.info(MODULE_TAG + 'start unregister wifi status observer');
238    wifi.off('wifiStateChange');
239  }
240
241  registerWiFiConnectionObserver(callback) {
242    LogUtil.info(MODULE_TAG + 'start register wifi connection observer');
243    wifi.on('wifiConnectionChange', callback);
244  }
245
246  unregisterWiFiConnectionObserver() {
247    LogUtil.info(MODULE_TAG + 'start unregister wifi connection observer');
248    try {
249      if (wifi.isWifiActive()) {
250        wifi.off('wifiConnectionChange');
251      }
252    } catch (error) {
253      let e: BusinessError = error as BusinessError;
254      LogUtil.error(MODULE_TAG + `off failed errorCode: ${e.code},  Message: ${e.message}`);
255    }
256  }
257
258  setUserSelectedAp(apInfo?: any) {
259    if (apInfo === null || typeof apInfo === 'undefined') {
260      this.userSelectedAp = new ApScanResult();
261    }
262    this.userSelectedAp = new ApScanResult(apInfo);
263  }
264
265  isSavedAp(ssid: string): boolean {
266    let deviceConfigs: any[] = wifi.getDeviceConfigs();
267    for (let i = 0; i < deviceConfigs.length; i++) {
268      if (ssid === deviceConfigs[i].ssid) {
269        return true;
270      }
271    }
272    return false;
273  }
274
275  isWiFiActive(): boolean {
276    const isActive: boolean = wifi.isWifiActive();
277    LogUtil.info(MODULE_TAG + 'check WiFi active status is : ' + isActive);
278    return isActive;
279  }
280
281  isWiFiConnected(): boolean {
282    let ret = wifi.isConnected();
283    LogUtil.info(MODULE_TAG + 'check WiFi connected status is : ' + ret);
284    return ret;
285  }
286
287  enableWiFi() {
288    if (wifi.isWifiActive() === true) {
289      LogUtil.info(MODULE_TAG + 'wifi is already active');
290      return;
291    }
292    try {
293      wifi.enableWifi();
294    }catch(error){
295      LogUtil.info(MODULE_TAG + "enable failed:" + JSON.stringify(error));
296    }
297  }
298
299  disableWifi() {
300    this.setUserSelectedAp(null);
301
302    if (wifi.isWifiActive() !== true) {
303      LogUtil.info(MODULE_TAG + 'wifi is already inactive');
304      return;
305    }
306    try {
307      wifi.disableWifi();
308    }catch(error){
309      LogUtil.info(MODULE_TAG + "disAble failed:" + JSON.stringify(error));
310    }
311  }
312
313  scanWiFi() {
314    try {
315      wifi.startScan()
316    } catch (error) {
317      let e: BusinessError = error as BusinessError;
318      LogUtil.error(MODULE_TAG + `startScan failed errorCode: ${e.code},  Message: ${e.message}`);
319    }
320  }
321
322  connectWiFi(password: string) {
323    let apInfo = this.userSelectedAp.getApInfo();
324    let ret = false;
325    let connectParam: wifi.WifiDeviceConfig = {
326      "ssid": apInfo.ssid,
327      "bssid": apInfo.bssid,
328      "preSharedKey": password,
329      "isHiddenSsid": false, // we don't support connect to hidden ap yet
330      "securityType": apInfo.securityType
331    };
332    LogUtil.info(MODULE_TAG + 'disconnect WiFi isConnected is ' + wifi.isConnected());
333    if (wifi.isConnected() === true) {
334      wifi.disconnect();
335      LogUtil.info(MODULE_TAG + 'disconnect WiFi ret is ' + ret);
336      this.registerWiFiConnectionObserver((code: Number) => {
337        if (code === 0) {
338          try {
339            wifi.connectToDevice(connectParam);
340            this.unregisterWiFiConnectionObserver();
341          } catch (error) {
342            let e: BusinessError = error as BusinessError;
343            LogUtil.error(MODULE_TAG + `connectToDevice failed errorCode: ${e.code},  Message: ${e.message}`);
344          }
345        }
346      })
347    } else {
348      try {
349        wifi.connectToDevice(connectParam);
350        LogUtil.info(MODULE_TAG + 'connect WiFi ret is ' + ret);
351      } catch (error) {
352        let e: BusinessError = error as BusinessError;
353        LogUtil.error(MODULE_TAG + `connectToDevice failed errorCode: ${e.code},  Message: ${e.message}`);
354      }
355    }
356    return ret;
357  }
358
359  /**
360   * Disconnect wifi
361   */
362  disconnectWiFi() {
363    this.setUserSelectedAp(null);
364
365    let ret = wifi.disconnect();
366    LogUtil.info(MODULE_TAG + 'disconnect WiFi result is : ' + ret);
367    return ret;
368  }
369
370  getSignalIntensity(apInfo: WifiScanInfo) {
371    let result = wifi.getSignalLevel(apInfo.rssi, apInfo.band);
372    if (result <= 1) {
373      return WiFiIntensityMap.BAD;
374    }
375    if (result <= 2) {
376      return WiFiIntensityMap.NORMAL;
377    }
378    if (result <= 3) {
379      return WiFiIntensityMap.WELL;
380    }
381    return WiFiIntensityMap.GOOD;
382  }
383
384  getEncryptMethod(apInfo: WifiScanInfo) {
385    if (apInfo.securityType === 1) {
386      return WiFiEncryptMethodMap.OPEN;
387    }
388    if (apInfo.securityType === 2) {
389      return WiFiEncryptMethodMap.WEP;
390    }
391    return WiFiEncryptMethodMap.WPA2;
392  }
393
394  getLinkInfo() {
395    return this.linkedApInfo;
396  }
397
398  removeDeviceConfig(apInfo: WifiScanInfo) {
399    LogUtil.info(MODULE_TAG + 'start to removeDeviceConfig');
400    let deviceConfigs: any[] = wifi.getDeviceConfigs();
401    let networkId: number = -1;
402    for (let i = 0; i < deviceConfigs.length; i++) {
403      if (deviceConfigs[i].ssid === apInfo.ssid) {
404        networkId = deviceConfigs[i].netId;
405        break;
406      }
407    }
408    if (networkId === -1) {
409      return;
410    }
411    LogUtil.info(MODULE_TAG + 'start to removeDevice');
412    wifi.removeDevice(networkId);
413  }
414
415  connectByDeviceConfig(apInfo: WifiScanInfo) {
416    let deviceConfigs: any[] = wifi.getDeviceConfigs();
417    // find the wifi device config
418    for (let i = 0; i < deviceConfigs.length; i++) {
419      if (deviceConfigs[i].ssid === apInfo.ssid) {
420        let ret = wifi.connectToDevice(deviceConfigs[i]);
421        LogUtil.info(MODULE_TAG + 'connect ret for : ' + i + ' = ' + ret);
422      }
423    }
424    LogUtil.info(MODULE_TAG + 'end connect by device config');
425  }
426
427  refreshApScanResults() {
428    wifi.getLinkedInfo((err: BusinessError, result: wifi.WifiLinkedInfo) => {
429      if (err) {
430        LogUtil.info(MODULE_TAG + 'get linked info failed');
431        return;
432      }
433      LogUtil.info(MODULE_TAG + 'scan get linked info succeed');
434      this.linkedApInfo = result;
435    });
436
437    let results: wifi.WifiScanInfo[] = wifi.getScanInfoList()
438    LogUtil.info(MODULE_TAG + 'get scan info succeed');
439
440    function removeDuplicateResults(arr: any[]): ApScanResult[] {
441      let results: ApScanResult[] = [];
442      for (let i = 0; i < arr.length; i++) {
443        let apResult = new ApScanResult(arr[i]);
444        if (apResult.isValidAp()) {
445          results.push(apResult);
446        }
447      }
448      return ApScanResult.filter(results);
449    };
450
451      function removeConnectedAp(arr: ApScanResult[], needRemove: ApScanResult) {
452        let index = ApScanResult.index(arr, needRemove);
453        if (index !== -1) {
454          arr.splice(index, 1);
455        }
456        return arr;
457      }
458
459      function addSavedConfigFlag(aps: ApScanResult[]): ApScanResult[] {
460        let configs: ApScanResult[] = [];
461        let deviceConfigs: any[] = wifi.getDeviceConfigs();
462        for (let i = 0; i < deviceConfigs.length; i++) {
463          let temp = new ApScanResult(deviceConfigs[i]);
464          configs.push(temp);
465        }
466        for (let i = 0; i < configs.length; i++) {
467          let index = ApScanResult.index(aps, configs[i]);
468          if (index !== -1) {
469            let item = aps[index];
470            item.updateSavedStatus(true);
471            aps.splice(index, 1);
472            aps.unshift(item);
473          }
474        }
475        return aps;
476      }
477
478      function addConnectStatusFlag(arr: ApScanResult[], linked: any): ApScanResult {
479        let ap: ApScanResult = new ApScanResult();
480        for (let i = 0; i < arr.length; i++) {
481          if (arr[i].getApInfo().ssid === linked.ssid) {
482            ap = arr[i];
483            break;
484          }
485        }
486        ap.updateConnectStatus(linked.connState);
487        return ap;
488      }
489
490      function unshiftConnectingAp(arr: ApScanResult[], ap: ApScanResult): ApScanResult[] {
491        let index = ApScanResult.index(arr, ap);
492        if (index !== -1) {
493          arr.splice(index, 1);
494          arr.unshift(ap);
495        }
496        return arr;
497      }
498
499      // step 1 : remove duplicate ap info
500      let scanResults: ApScanResult[] = removeDuplicateResults(results);
501      LogUtil.info(MODULE_TAG + 'scan results items length is : ' + scanResults.length);
502
503      // step 2 : add saved config flags
504      scanResults = addSavedConfigFlag(scanResults);
505      scanResults.sort(ApScanResult.compare);
506
507    // step 3 : add wifi summary
508    if (this.linkedApInfo) {
509      let linkInfoResult: ApScanResult = addConnectStatusFlag(scanResults, this.linkedApInfo);
510      if (linkInfoResult.isConnected()) {
511        AppStorage.SetOrCreate('slnetId', this.linkedApInfo.networkId + '');
512        LogUtil.info(MODULE_TAG + 'scan connected');
513        scanResults = removeConnectedAp(scanResults, linkInfoResult);
514        AppStorage.SetOrCreate('slConnectedWifi', linkInfoResult.renderToListModel());
515      } else {
516        LogUtil.info(MODULE_TAG + 'scan not connected');
517        scanResults = unshiftConnectingAp(scanResults, linkInfoResult);
518        AppStorage.SetOrCreate('slConnectedWifi', (new ApScanResult()).renderToListModel());
519      }
520    }
521    LogUtil.info(MODULE_TAG + 'scan list results');
522    AppStorage.SetOrCreate('slWiFiLists', scanResults.map((item) => {
523      return item.renderToListModel();
524    }));
525  }
526
527  startScanTask() {
528    LogUtil.info(MODULE_TAG + 'start the wifi scan task');
529
530    if (this.scanTaskId !== Undefined_TaskId) {
531      clearInterval(this.scanTaskId);
532      this.scanTaskId = Undefined_TaskId;
533    }
534
535    this.scanTaskId = setInterval(() => {
536      if (this.isWiFiActive() && this.isScanning) {
537        this.refreshApScanResults();
538        return;
539      }
540      if (this.isWiFiActive() === true) {
541        LogUtil.info(MODULE_TAG + 'scan wifi started');
542        this.scanWiFi();
543        this.isScanning = true;
544        this.refreshApScanResults();
545      }
546    }, 5000);
547  }
548
549  stopScanTask() {
550    LogUtil.info(MODULE_TAG + 'stop the wifi scan task');
551    if (this.scanTaskId !== Undefined_TaskId) {
552      clearInterval(this.scanTaskId);
553      this.scanTaskId = Undefined_TaskId;
554    }
555    this.isScanning = false;
556  }
557}
558
559let wifiModel = new WifiModel();
560export default wifiModel as WifiModel;
561