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 setUserSelectedAp(apInfo?: any) { 252 if (apInfo === null || typeof apInfo === 'undefined') { 253 this.userSelectedAp = new ApScanResult(); 254 } 255 this.userSelectedAp = new ApScanResult(apInfo); 256 } 257 258 isSavedAp(ssid: string): boolean { 259 let deviceConfigs: any[] = wifi.getDeviceConfigs(); 260 for (let i = 0; i < deviceConfigs.length; i++) { 261 if (ssid === deviceConfigs[i].ssid) { 262 return true; 263 } 264 } 265 return false; 266 } 267 268 isWiFiActive(): boolean { 269 const isActive: boolean = wifi.isWifiActive(); 270 LogUtil.info(MODULE_TAG + 'check WiFi active status is : ' + isActive); 271 return isActive; 272 } 273 274 isWiFiConnected(): boolean { 275 let ret = wifi.isConnected(); 276 LogUtil.info(MODULE_TAG + 'check WiFi connected status is : ' + ret); 277 return ret; 278 } 279 280 enableWiFi() { 281 if (wifi.isWifiActive() === true) { 282 LogUtil.info(MODULE_TAG + 'wifi is already active'); 283 return; 284 } 285 let ret: boolean = wifi.enableWifi(); 286 LogUtil.info(MODULE_TAG + 'enable WiFi result is : ' + ret); 287 return ret; 288 } 289 290 disableWifi() { 291 this.setUserSelectedAp(null); 292 293 if (wifi.isWifiActive() !== true) { 294 LogUtil.info(MODULE_TAG + 'wifi is already inactive'); 295 return; 296 } 297 const ret: boolean = wifi.disableWifi(); 298 LogUtil.info(MODULE_TAG + 'disable WiFi result is : ' + ret); 299 } 300 301 scanWiFi(): boolean { 302 const ret: boolean = wifi.scan(); 303 LogUtil.info(MODULE_TAG + 'start scan WiFi result is : ' + ret); 304 return ret; 305 } 306 307 connectWiFi(password: string) { 308 let apInfo = this.userSelectedAp.getApInfo(); 309 let ret = false; 310 let connectParam: any = { 311 "ssid": apInfo.ssid, 312 "bssid": apInfo.bssid, 313 "preSharedKey": password, 314 "isHiddenSsid": false, // we don't support connect to hidden ap yet 315 "securityType": apInfo.securityType 316 }; 317 LogUtil.info(MODULE_TAG + 'disconnect WiFi isConnected is ' + wifi.isConnected()); 318 if (wifi.isConnected() === true) { 319 ret = wifi.disconnect(); 320 LogUtil.info(MODULE_TAG + 'disconnect WiFi ret is ' + ret); 321 this.registerWiFiConnectionObserver((code: Number) => { 322 if (code === 0) { 323 ret = wifi.connectToDevice(connectParam); 324 this.unregisterWiFiConnectionObserver(); 325 } 326 }) 327 }else{ 328 ret = wifi.connectToDevice(connectParam); 329 LogUtil.info(MODULE_TAG + 'connect WiFi ret is ' + ret); 330 } 331 return ret; 332 } 333 334 /** 335 * Disconnect wifi 336 */ 337 disconnectWiFi() { 338 this.setUserSelectedAp(null); 339 340 let ret = wifi.disconnect(); 341 LogUtil.info(MODULE_TAG + 'disconnect WiFi result is : ' + ret); 342 return ret; 343 } 344 345 getSignalIntensity(apInfo: WifiScanInfo) { 346 let result = wifi.getSignalLevel(apInfo.rssi, apInfo.band); 347 if (result <= 1) { 348 return WiFiIntensityMap.BAD; 349 } 350 if (result <= 2) { 351 return WiFiIntensityMap.NORMAL; 352 } 353 if (result <= 3) { 354 return WiFiIntensityMap.WELL; 355 } 356 return WiFiIntensityMap.GOOD; 357 } 358 359 getEncryptMethod(apInfo: WifiScanInfo) { 360 if (apInfo.securityType === 1) { 361 return WiFiEncryptMethodMap.OPEN; 362 } 363 if (apInfo.securityType === 2) { 364 return WiFiEncryptMethodMap.WEP; 365 } 366 return WiFiEncryptMethodMap.WPA2; 367 } 368 369 getLinkInfo() { 370 return this.linkedApInfo; 371 } 372 373 removeDeviceConfig(apInfo: WifiScanInfo) { 374 LogUtil.info(MODULE_TAG + 'start to removeDeviceConfig'); 375 let deviceConfigs: any[] = wifi.getDeviceConfigs(); 376 let networkId: number = -1; 377 for (let i = 0; i < deviceConfigs.length; i++) { 378 if (deviceConfigs[i].ssid === apInfo.ssid) { 379 networkId = deviceConfigs[i].netId; 380 break; 381 } 382 } 383 if (networkId === -1) { 384 return; 385 } 386 LogUtil.info(MODULE_TAG + 'start to removeDevice'); 387 let ret = wifi.removeDevice(networkId); 388 LogUtil.info(MODULE_TAG + 'remove device config : ' + ret); 389 } 390 391 connectByDeviceConfig(apInfo: WifiScanInfo) { 392 let deviceConfigs: any[] = wifi.getDeviceConfigs(); 393 // find the wifi device config 394 for (let i = 0; i < deviceConfigs.length; i++) { 395 if (deviceConfigs[i].ssid === apInfo.ssid) { 396 let ret = wifi.connectToDevice(deviceConfigs[i]); 397 LogUtil.info(MODULE_TAG + 'connect ret for : ' + i + ' = ' + ret); 398 } 399 } 400 LogUtil.info(MODULE_TAG + 'end connect by device config'); 401 } 402 403 refreshApScanResults() { 404 wifi.getLinkedInfo((err, result) => { 405 if (err) { 406 LogUtil.info(MODULE_TAG + 'get linked info failed'); 407 return; 408 } 409 LogUtil.info(MODULE_TAG + 'scan get linked info succeed'); 410 this.linkedApInfo = result; 411 }); 412 413 wifi.getScanInfos((err, results) => { 414 if (err) { 415 LogUtil.info(MODULE_TAG + "get scan info failed"); 416 return; 417 } 418 LogUtil.info(MODULE_TAG + 'get scan info succeed'); 419 function removeDuplicateResults(arr: any[]): ApScanResult[] { 420 let results: ApScanResult[] = []; 421 for (let i = 0; i < arr.length; i++) { 422 let apResult = new ApScanResult(arr[i]); 423 if (apResult.isValidAp()) { 424 results.push(apResult); 425 } 426 } 427 return ApScanResult.filter(results); 428 }; 429 430 function removeConnectedAp(arr: ApScanResult[], needRemove: ApScanResult) { 431 let index = ApScanResult.index(arr, needRemove); 432 if (index !== -1) { 433 arr.splice(index, 1); 434 } 435 return arr; 436 } 437 438 function addSavedConfigFlag(aps: ApScanResult[]): ApScanResult[] { 439 let configs: ApScanResult[] = []; 440 let deviceConfigs: any[] = wifi.getDeviceConfigs(); 441 for (let i = 0; i < deviceConfigs.length; i++) { 442 let temp = new ApScanResult(deviceConfigs[i]); 443 configs.push(temp); 444 } 445 for (let i = 0; i < configs.length; i++) { 446 let index = ApScanResult.index(aps, configs[i]); 447 if (index !== -1) { 448 let item = aps[index]; 449 item.updateSavedStatus(true); 450 aps.splice(index, 1); 451 aps.unshift(item); 452 } 453 } 454 return aps; 455 } 456 457 function addConnectStatusFlag(arr: ApScanResult[], linked: any): ApScanResult { 458 let ap: ApScanResult = new ApScanResult(); 459 for (let i = 0; i < arr.length; i++) { 460 if (arr[i].getApInfo().ssid === linked.ssid) { 461 ap = arr[i]; 462 break; 463 } 464 } 465 ap.updateConnectStatus(linked.connState); 466 return ap; 467 } 468 469 function unshiftConnectingAp(arr: ApScanResult[], ap: ApScanResult): ApScanResult[] { 470 let index = ApScanResult.index(arr, ap); 471 if (index !== -1) { 472 arr.splice(index, 1); 473 arr.unshift(ap); 474 } 475 return arr; 476 } 477 478 // step 1 : remove duplicate ap info 479 let scanResults: ApScanResult[] = removeDuplicateResults(results); 480 LogUtil.info(MODULE_TAG + 'scan results items length is : ' + scanResults.length); 481 482 // step 2 : add saved config flags 483 scanResults = addSavedConfigFlag(scanResults); 484 scanResults.sort(ApScanResult.compare); 485 486 // step 3 : add wifi summary 487 if (this.linkedApInfo !== null && typeof this.linkedApInfo !== 'undefined') { 488 let linkInfoResult: ApScanResult = addConnectStatusFlag(scanResults, this.linkedApInfo); 489 if (linkInfoResult.isConnected()) { 490 LogUtil.info(MODULE_TAG + 'scan connected'); 491 scanResults = removeConnectedAp(scanResults, linkInfoResult); 492 AppStorage.SetOrCreate('slConnectedWifi', linkInfoResult.renderToListModel()); 493 } else { 494 LogUtil.info(MODULE_TAG + 'scan not connected'); 495 scanResults = unshiftConnectingAp(scanResults, linkInfoResult); 496 AppStorage.SetOrCreate('slConnectedWifi', (new ApScanResult()).renderToListModel()); 497 } 498 } 499 LogUtil.info(MODULE_TAG + 'scan list results'); 500 AppStorage.SetOrCreate('slWiFiLists', scanResults.map((item) => { 501 return item.renderToListModel(); 502 })); 503 }); 504 } 505 506 startScanTask() { 507 LogUtil.info(MODULE_TAG + 'start the wifi scan task'); 508 509 if (this.scanTaskId !== Undefined_TaskId) { 510 clearInterval(this.scanTaskId); 511 this.scanTaskId = Undefined_TaskId; 512 } 513 514 this.scanTaskId = setInterval(() => { 515 if (this.isWiFiActive() === true) { 516 LogUtil.info(MODULE_TAG + 'scan wifi started'); 517 this.scanWiFi(); 518 this.isScanning = true; 519 this.refreshApScanResults(); 520 } 521 }, 5000); 522 } 523 524 stopScanTask() { 525 LogUtil.info(MODULE_TAG + 'stop the wifi scan task'); 526 if (this.scanTaskId !== Undefined_TaskId) { 527 clearInterval(this.scanTaskId); 528 this.scanTaskId = Undefined_TaskId; 529 } 530 this.isScanning = false; 531 } 532} 533 534let wifiModel = new WifiModel(); 535export default wifiModel as WifiModel; 536