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