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(): { settingIcon: string, settingSummary: number, settingTitle: string, settingValue: string, 140 settingArrow: string, settingArrowStyle: string, settingUri: string, apInfo: WifiScanInfo } { 141 function generateArrow(that: ApScanResult): string { 142 let signalLevel: string = that.getSignalLevel().toString(); 143 let lockPrefix: string = 'lock_'; 144 if (that.isSecurityAp() !== true) { 145 lockPrefix = ''; 146 } 147 let result: string = `/res/image/ic_wifi_${lockPrefix}signal_${signalLevel}_dark.svg`; 148 return result; 149 } 150 151 function generateSummary(that: ApScanResult): number { 152 if (that.isConnected()) { 153 return WiFiSummaryMap.CONNECTED; 154 } 155 if (that.connectStatus === ConnState.CONNECTING) { 156 return WiFiSummaryMap.CONNECTING; 157 } 158 if (that.connectStatus === ConnState.OBTAINING_IPADDR) { 159 return WiFiSummaryMap.OBTAINING_IP; 160 } 161 if (that.isSavedConfig()) { 162 if (that.isSecurityAp()) { 163 return WiFiSummaryMap.SAVE_ENCRYPTED; 164 } else { 165 return WiFiSummaryMap.SAVE_OPEN; 166 } 167 } else { 168 if (that.isSecurityAp()) { 169 return WiFiSummaryMap.ENCRYPTED; 170 } else { 171 return WiFiSummaryMap.OPEN; 172 } 173 } 174 } 175 176 let ret = { 177 settingIcon: '', 178 settingSummary: generateSummary(this), 179 settingTitle: this.apInfo.ssid, 180 settingValue: '', 181 settingArrow: generateArrow(this), 182 settingArrowStyle: 'wifi', 183 settingUri: '', 184 apInfo: this.apInfo, 185 }; 186 return ret; 187 } 188 189 toString(): string { 190 return `apInfo is: ssid=${this.getApInfo().ssid} signal=${this.getSignalLevel()} isConnected=${this.isConnected()}`; 191 } 192 193 static compare(x: ApScanResult, y: ApScanResult): number { 194 let xApInfo = x.getApInfo(); 195 let yApInfo = y.getApInfo(); 196 // rssi value is negative number 197 return ((-xApInfo.rssi) - (-yApInfo.rssi)); 198 } 199 200 static filter(arr: ApScanResult[]): ApScanResult[] { 201 let hash = {}; 202 return arr.reduce((total, currItem) => { 203 if (!hash[currItem.getApInfo().ssid]) { 204 hash[currItem.getApInfo().ssid] = true; 205 total.push(currItem); 206 } 207 return total; 208 }, []); 209 } 210 211 static index(arr: ApScanResult[], target: ApScanResult): number { 212 return arr.map((item) => { 213 return item.getApInfo().ssid; 214 }).indexOf(target.getApInfo().ssid); 215 } 216} 217 218export class WifiModel extends BaseModel { 219 private userSelectedAp: ApScanResult = new ApScanResult(); 220 private linkedApInfo: any = undefined; 221 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 wifi.off('wifiConnectionChange'); 249 } 250 251 getDeviceConfigsInfo(ssid: string): wifi.WifiDeviceConfig { 252 let deviceConfigs: wifi.WifiDeviceConfig[] = wifi.getDeviceConfigs(); 253 for (let i = 0; i < deviceConfigs.length; i++) { 254 if (ssid === deviceConfigs[i].ssid) { 255 return deviceConfigs[i]; 256 } 257 } 258 return null; 259 } 260 261 setUserSelectedAp(apInfo?: any) { 262 if (apInfo === null || typeof apInfo === 'undefined') { 263 this.userSelectedAp = new ApScanResult(); 264 } 265 this.userSelectedAp = new ApScanResult(apInfo); 266 } 267 268 isSavedAp(ssid: string): boolean { 269 let deviceConfigs: any[] = wifi.getDeviceConfigs(); 270 for (let i = 0; i < deviceConfigs.length; i++) { 271 if (ssid === deviceConfigs[i].ssid) { 272 return true; 273 } 274 } 275 return false; 276 } 277 278 isWiFiActive(): boolean { 279 const isActive: boolean = wifi.isWifiActive(); 280 LogUtil.info(MODULE_TAG + 'check WiFi active status is : ' + isActive); 281 return isActive; 282 } 283 284 isWiFiConnected(): boolean { 285 let ret = wifi.isConnected(); 286 LogUtil.info(MODULE_TAG + 'check WiFi connected status is : ' + ret); 287 return ret; 288 } 289 290 enableWiFi() { 291 if (wifi.isWifiActive() === true) { 292 LogUtil.info(MODULE_TAG + 'wifi is already active'); 293 return; 294 } 295 let ret: boolean = wifi.enableWifi(); 296 LogUtil.info(MODULE_TAG + 'enable WiFi result is : ' + ret); 297 return ret; 298 } 299 300 disableWifi() { 301 this.setUserSelectedAp(null); 302 303 if (wifi.isWifiActive() !== true) { 304 LogUtil.info(MODULE_TAG + 'wifi is already inactive'); 305 return; 306 } 307 const ret: boolean = wifi.disableWifi(); 308 LogUtil.info(MODULE_TAG + 'disable WiFi result is : ' + ret); 309 } 310 311 scanWiFi(): boolean { 312 const ret: boolean = wifi.scan(); 313 LogUtil.info(MODULE_TAG + 'start scan WiFi result is : ' + ret); 314 return ret; 315 } 316 317 connectWiFi(password: string) { 318 let apInfo = this.userSelectedAp.getApInfo(); 319 let ret = false; 320 let connectParam: any = { 321 "ssid": apInfo.ssid, 322 "bssid": apInfo.bssid, 323 "preSharedKey": password, 324 "isHiddenSsid": false, // we don't support connect to hidden ap yet 325 "securityType": apInfo.securityType 326 }; 327 LogUtil.info(MODULE_TAG + 'disconnect WiFi isConnected is ' + wifi.isConnected()); 328 if (wifi.isConnected() === true) { 329 ret = wifi.disconnect(); 330 LogUtil.info(MODULE_TAG + 'disconnect WiFi ret is ' + ret); 331 this.registerWiFiConnectionObserver((code: Number) => { 332 if (code === 0) { 333 ret = wifi.connectToDevice(connectParam); 334 this.unregisterWiFiConnectionObserver(); 335 } 336 }) 337 }else{ 338 ret = wifi.connectToDevice(connectParam); 339 LogUtil.info(MODULE_TAG + 'connect WiFi ret is ' + ret); 340 } 341 return ret; 342 } 343 344 /** 345 * Disconnect wifi 346 */ 347 disconnectWiFi() { 348 this.setUserSelectedAp(null); 349 350 let ret = wifi.disconnect(); 351 LogUtil.info(MODULE_TAG + 'disconnect WiFi result is : ' + ret); 352 return ret; 353 } 354 355 getSignalIntensity(apInfo: WifiScanInfo) { 356 let result = wifi.getSignalLevel(apInfo.rssi, apInfo.band); 357 if (result <= 1) { 358 return WiFiIntensityMap.BAD; 359 } 360 if (result <= 2) { 361 return WiFiIntensityMap.NORMAL; 362 } 363 if (result <= 3) { 364 return WiFiIntensityMap.WELL; 365 } 366 return WiFiIntensityMap.GOOD; 367 } 368 369 getEncryptMethod(apInfo: WifiScanInfo) { 370 if (apInfo.securityType === 1) { 371 return WiFiEncryptMethodMap.OPEN; 372 } 373 if (apInfo.securityType === 2) { 374 return WiFiEncryptMethodMap.WEP; 375 } 376 return WiFiEncryptMethodMap.WPA2; 377 } 378 379 getLinkInfo() { 380 return this.linkedApInfo; 381 } 382 383 removeDeviceConfig(apInfo: WifiScanInfo) { 384 LogUtil.info(MODULE_TAG + 'start to removeDeviceConfig'); 385 let deviceConfigs: any[] = wifi.getDeviceConfigs(); 386 let networkId: number = -1; 387 for (let i = 0; i < deviceConfigs.length; i++) { 388 if (deviceConfigs[i].ssid === apInfo.ssid) { 389 networkId = deviceConfigs[i].netId; 390 break; 391 } 392 } 393 if (networkId === -1) { 394 return; 395 } 396 LogUtil.info(MODULE_TAG + 'start to removeDevice'); 397 let ret = wifi.removeDevice(networkId); 398 LogUtil.info(MODULE_TAG + 'remove device config : ' + ret); 399 } 400 401 connectByDeviceConfig(apInfo: WifiScanInfo) { 402 let deviceConfigs: any[] = wifi.getDeviceConfigs(); 403 // find the wifi device config 404 for (let i = 0; i < deviceConfigs.length; i++) { 405 if (deviceConfigs[i].ssid === apInfo.ssid) { 406 let ret = wifi.connectToDevice(deviceConfigs[i]); 407 LogUtil.info(MODULE_TAG + 'connect ret for : ' + i + ' = ' + ret); 408 } 409 } 410 LogUtil.info(MODULE_TAG + 'end connect by device config'); 411 } 412 413 refreshApScanResults() { 414 wifi.getLinkedInfo((err, result) => { 415 if (err) { 416 LogUtil.info(MODULE_TAG + 'get linked info failed'); 417 return; 418 } 419 LogUtil.info(MODULE_TAG + 'scan get linked info succeed'); 420 this.linkedApInfo = result; 421 }); 422 423 wifi.getScanInfos((err, results) => { 424 if (err) { 425 LogUtil.info(MODULE_TAG + "get scan info failed"); 426 return; 427 } 428 LogUtil.info(MODULE_TAG + 'get scan info succeed'); 429 function removeDuplicateResults(arr: any[]): ApScanResult[] { 430 let results: ApScanResult[] = []; 431 for (let i = 0; i < arr.length; i++) { 432 let apResult = new ApScanResult(arr[i]); 433 if (apResult.isValidAp()) { 434 results.push(apResult); 435 } 436 } 437 return ApScanResult.filter(results); 438 }; 439 440 function removeConnectedAp(arr: ApScanResult[], needRemove: ApScanResult) { 441 let index = ApScanResult.index(arr, needRemove); 442 if (index !== -1) { 443 arr.splice(index, 1); 444 } 445 return arr; 446 } 447 448 function addSavedConfigFlag(aps: ApScanResult[]): ApScanResult[] { 449 let configs: ApScanResult[] = []; 450 let deviceConfigs: any[] = wifi.getDeviceConfigs(); 451 for (let i = 0; i < deviceConfigs.length; i++) { 452 let temp = new ApScanResult(deviceConfigs[i]); 453 configs.push(temp); 454 } 455 for (let i = 0; i < configs.length; i++) { 456 let index = ApScanResult.index(aps, configs[i]); 457 if (index !== -1) { 458 let item = aps[index]; 459 item.updateSavedStatus(true); 460 aps.splice(index, 1); 461 aps.unshift(item); 462 } 463 } 464 return aps; 465 } 466 467 function addConnectStatusFlag(arr: ApScanResult[], linked: any): ApScanResult { 468 let ap: ApScanResult = new ApScanResult(); 469 for (let i = 0; i < arr.length; i++) { 470 if (arr[i].getApInfo().ssid === linked.ssid) { 471 ap = arr[i]; 472 break; 473 } 474 } 475 ap.updateConnectStatus(linked.connState); 476 return ap; 477 } 478 479 function unshiftConnectingAp(arr: ApScanResult[], ap: ApScanResult): ApScanResult[] { 480 let index = ApScanResult.index(arr, ap); 481 if (index !== -1) { 482 arr.splice(index, 1); 483 arr.unshift(ap); 484 } 485 return arr; 486 } 487 488 // step 1 : remove duplicate ap info 489 let scanResults: ApScanResult[] = removeDuplicateResults(results); 490 LogUtil.info(MODULE_TAG + 'scan results items length is : ' + scanResults.length); 491 492 // step 2 : add saved config flags 493 scanResults = addSavedConfigFlag(scanResults); 494 scanResults.sort(ApScanResult.compare); 495 496 // step 3 : add wifi summary 497 if (this.linkedApInfo !== null && typeof this.linkedApInfo !== 'undefined') { 498 let linkInfoResult: ApScanResult = addConnectStatusFlag(scanResults, this.linkedApInfo); 499 if (linkInfoResult.isConnected()) { 500 LogUtil.info(MODULE_TAG + 'scan connected'); 501 scanResults = removeConnectedAp(scanResults, linkInfoResult); 502 AppStorage.SetOrCreate('slConnectedWifi', linkInfoResult.renderToListModel()); 503 } else { 504 LogUtil.info(MODULE_TAG + 'scan not connected'); 505 scanResults = unshiftConnectingAp(scanResults, linkInfoResult); 506 AppStorage.SetOrCreate('slConnectedWifi', (new ApScanResult()).renderToListModel()); 507 } 508 } 509 LogUtil.info(MODULE_TAG + 'scan list results'); 510 AppStorage.SetOrCreate('slWiFiLists', scanResults.map((item) => { 511 return item.renderToListModel(); 512 })); 513 }); 514 } 515 516 startScanTask() { 517 LogUtil.info(MODULE_TAG + 'start the wifi scan task'); 518 519 if (this.scanTaskId !== Undefined_TaskId) { 520 clearInterval(this.scanTaskId); 521 this.scanTaskId = Undefined_TaskId; 522 } 523 524 this.scanTaskId = setInterval(() => { 525 if (this.isWiFiActive() === true) { 526 LogUtil.info(MODULE_TAG + 'scan wifi started'); 527 this.scanWiFi(); 528 this.isScanning = true; 529 this.refreshApScanResults(); 530 } 531 }, 5000); 532 } 533 534 stopScanTask() { 535 LogUtil.info(MODULE_TAG + 'stop the wifi scan task'); 536 if (this.scanTaskId !== Undefined_TaskId) { 537 clearInterval(this.scanTaskId); 538 this.scanTaskId = Undefined_TaskId; 539 } 540 this.isScanning = false; 541 } 542} 543 544let wifiModel = new WifiModel(); 545export default wifiModel as WifiModel; 546