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 BaseModel from '../../../../../../../common/utils/src/main/ets/default/model/BaseModel'; 16import LogUtil from '../../../../../../../common/utils/src/main/ets/default/baseUtil/LogUtil'; 17import ConfigData from '../../../../../../../common/utils/src/main/ets/default/baseUtil/ConfigData'; 18import Log from '../../../../../../../common/utils/src/main/ets/default/baseUtil/LogDecorator'; 19import bluetooth from '@ohos.bluetooth'; 20import bluetoothManager from '@ohos.bluetoothManager'; 21import AboutDeviceModel from '../../model/aboutDeviceImpl/AboutDeviceModel'; 22 23export enum ProfileCode { 24 CODE_BT_PROFILE_A2DP_SINK = 0, 25 CODE_BT_PROFILE_A2DP_SOURCE, 26 CODE_BT_PROFILE_AVRCP_CT, 27 CODE_BT_PROFILE_AVRCP_TG, 28 CODE_BT_PROFILE_HANDS_FREE_AUDIO_GATEWAY, 29 CODE_BT_PROFILE_HANDS_FREE_UNIT, 30 CODE_BT_PROFILE_HID_HOST, 31 CODE_BT_PROFILE_PAN_NETWORK, 32 CODE_BT_PROFILE_PBAP_CLIENT, 33 CODE_BT_PROFILE_PBAP_SERVER, 34}; 35 36export enum ProfileConnectionState { 37 /** the current profile is disconnected */ 38 STATE_DISCONNECTED = 0, 39 /** the current profile is being connected */ 40 STATE_CONNECTING = 1, 41 /** the current profile is connected */ 42 STATE_CONNECTED = 2, 43 /** the current profile is being disconnected */ 44 STATE_DISCONNECTING = 3 45} 46 47export enum BondState { 48 /** Indicate the bond state is invalid */ 49 BOND_STATE_INVALID = 0, 50 /** Indicate the bond state is bonding */ 51 BOND_STATE_BONDING = 1, 52 /** Indicate the bond state is bonded*/ 53 BOND_STATE_BONDED = 2 54} 55 56export enum DeviceType { 57 BLUETOOTH = '1', 58 HEADPHONE = '2', 59 PHONE = '3', 60 COMPUTER = '4', 61 WATCH = '5' 62} 63 64export enum BluetoothErrorCode { 65 SUCCESS = -1, 66 HOLD_PAIRING_MODE = 1, 67 APP_PAIR = 2, 68 PAIR_FAILED = 3, 69 DEVICE_ILLEGAL = 4, 70 CONNECT_FAILED = 5 71} 72 73enum BluetoothState { 74 /** Indicates the local Bluetooth is off */ 75 STATE_OFF = 0, 76 /** Indicates the local Bluetooth is turning on */ 77 STATE_TURNING_ON = 1, 78 /** Indicates the local Bluetooth is on, and ready for use */ 79 STATE_ON = 2, 80 /** Indicates the local Bluetooth is turning off */ 81 STATE_TURNING_OFF = 3, 82 /** Indicates the local Bluetooth is turning LE mode on */ 83 STATE_BLE_TURNING_ON = 4, 84 /** Indicates the local Bluetooth is in LE only mode */ 85 STATE_BLE_ON = 5, 86 /** Indicates the local Bluetooth is turning off LE only mode */ 87 STATE_BLE_TURNING_OFF = 6 88} 89 90/** 91 * bluetooth service class 92 */ 93export class BluetoothModel extends BaseModel { 94 private TAG = ConfigData.TAG + 'BluetoothModel '; 95 private profiles: any[] = new Array(10); 96 public canUse: boolean = false; 97 98 /** 99 * constructor 100 */ 101 constructor() { 102 super(); 103 try{ 104 LogUtil.info('bluetooth.getProfile start') 105 let profileId = bluetoothManager.ProfileId; 106 this.profiles[profileId.PROFILE_A2DP_SOURCE] = 107 bluetoothManager.getProfileInstance(profileId.PROFILE_A2DP_SOURCE); 108 this.profiles[profileId.PROFILE_HANDS_FREE_AUDIO_GATEWAY] = 109 bluetoothManager.getProfileInstance(profileId.PROFILE_HANDS_FREE_AUDIO_GATEWAY); 110 this.profiles[profileId.PROFILE_HID_HOST] = 111 bluetoothManager.getProfileInstance(profileId.PROFILE_HID_HOST); 112 LogUtil.info('bluetooth.getProfile end') 113 this.canUse = true; 114 } 115 catch(error){ 116 LogUtil.info('bluetooth.getProfile error') 117 this.canUse = false; 118 LogUtil.info(`BluetoothModel error: ${JSON.stringify(error)}.`); 119 } 120 } 121 122 123 /** 124 * Get Bluetooth status 125 * @return value of bluetooth.BluetoothState type 126 */ 127 getState(): number { 128 let bluetoothState = bluetooth.getState(); 129 LogUtil.info(`${this.TAG} getState: bluetoothState = ${bluetoothState}`); 130 return bluetoothState; 131 } 132 133 /** 134 * Get Bluetooth switch status 135 */ 136 isStateOn(): boolean { 137 let result = false; 138 let state = bluetooth.getState(); 139 LogUtil.info(`${this.TAG} isStateOn: state = ${state}`); 140 switch (state) { 141 case BluetoothState.STATE_ON: 142 result = true 143 break; 144 default: 145 break; 146 } 147 LogUtil.info(`${this.TAG} isStateOn: bluetoothState = ${result}`); 148 return result; 149 } 150 151 /** 152 * Subscribe Bluetooth switch status Change 153 */ 154 subscribeStateChange(callback: (data: boolean) => void): void { 155 LogUtil.info('bluetooth.subscribeStateChange start'); 156 bluetooth.on('stateChange', (data) => { 157 LogUtil.info(`${this.TAG} subscribeStateChange->stateChange data:${data}`); 158 if (callback) { 159 switch (data) { 160 case BluetoothState.STATE_ON: 161 let deviceName: string = AboutDeviceModel.getSystemName(); 162 let bluetoothName: string = bluetooth.getLocalName(); 163 LogUtil.info(`${this.TAG} subscribeStateChange get deviceName: ${deviceName}, bluetoothName: ${bluetoothName}`); 164 if(deviceName !== bluetoothName){ 165 LogUtil.info(`${this.TAG} subscribeStateChange deviceName != bluetoothName`) 166 bluetooth.setLocalName(deviceName); 167 } 168 bluetooth.setBluetoothScanMode(4, 0); 169 LogUtil.info(`${this.TAG} subscribeStateChange->stateChange return: true`); 170 callback(true) 171 break; 172 173 case BluetoothState.STATE_OFF: 174 LogUtil.info(`${this.TAG} subscribeStateChange->stateChange return: false`); 175 callback(false) 176 break; 177 178 default: 179 break; 180 } 181 } 182 }) 183 } 184 185 /** 186 * unsubscribe Bluetooth switch status Change 187 */ 188 unsubscribeStateChange(callback?: (data: boolean) => void): void { 189 LogUtil.info('bluetooth.unsubscribeStateChange start'); 190 bluetooth.off('stateChange', (data) => { 191 LogUtil.info(`${this.TAG} unsubscribeStateChange->stateChange data:${data}`); 192 if (callback) { 193 let result = false; 194 switch (data) { 195 case BluetoothState.STATE_ON: 196 LogUtil.info(`${this.TAG} unsubscribeStateChange->stateChange return : true`); 197 callback(true) 198 break; 199 case BluetoothState.STATE_OFF: 200 LogUtil.info(`${this.TAG} unsubscribeStateChange->stateChange return : false`); 201 callback(false) 202 break; 203 default: 204 break; 205 } 206 } 207 }) 208 } 209 210 /** 211 * Turn on Bluetooth 212 */ 213 @Log 214 enableBluetooth(): boolean { 215 return bluetooth.enableBluetooth(); 216 } 217 218 /** 219 * Turn off Bluetooth 220 */ 221 @Log 222 disableBluetooth(): boolean { 223 return bluetooth.disableBluetooth(); 224 } 225 226 /** 227 * Get local name 228 */ 229 getLocalName(): string { 230 return bluetooth.getLocalName(); 231 } 232 233 /** 234 * Set local name 235 */ 236 setLocalName(name: string): boolean { 237 return bluetooth.setLocalName(name); 238 } 239 240 /** 241 * Get paired device ids 242 */ 243 getPairedDeviceIds(): Array<string> { 244 return bluetooth.getPairedDevices(); 245 } 246 247 /** 248 * Start Bluetooth discovery 249 */ 250 @Log 251 startBluetoothDiscovery(): boolean { 252 return bluetooth.startBluetoothDiscovery(); 253 } 254 255 /** 256 * Stop Bluetooth discovery 257 */ 258 @Log 259 stopBluetoothDiscovery(): boolean { 260 return bluetooth.stopBluetoothDiscovery(); 261 } 262 263 /** 264 * Subscribe Bluetooth status Change 265 */ 266 subscribeBluetoothDeviceFind(callback: (data: Array<string>) => void): void { 267 LogUtil.info('bluetooth.subscribeBluetoothDeviceFind start'); 268 bluetooth.on('bluetoothDeviceFind', (data: Array<string>) => { 269 LogUtil.info(`${this.TAG} subscribeBluetoothDeviceFind->deviceFind callback`); 270 if (callback) { 271 callback(data) 272 } 273 }) 274 } 275 276 /** 277 * unsubscribe Bluetooth status Change 278 */ 279 unsubscribeBluetoothDeviceFind(callback?: (data: Array<string>) => void): void { 280 LogUtil.info('bluetooth.unsubscribeBluetoothDeviceFind start'); 281 bluetooth.off('bluetoothDeviceFind', (data) => { 282 LogUtil.info(`${this.TAG} unsubscribeBluetoothDeviceFind->deviceFind callback`); 283 if (callback) { 284 callback(data) 285 } 286 }) 287 } 288 289 /** 290 * Pair device 291 */ 292 pairDevice(deviceId: string): boolean { 293 return bluetooth.pairDevice(deviceId); 294 } 295 296 /** 297 * Subscribe PinRequired 298 */ 299 subscribePinRequired(callback: (data: { 300 deviceId: string; 301 pinCode: string; 302 }) => void): void { 303 LogUtil.info('bluetooth.subscribePinRequired start'); 304 bluetooth.on('pinRequired', (data: { 305 deviceId: string; 306 pinCode: string; 307 }) => { 308 LogUtil.info(`${this.TAG} subscribePinRequired->pinRequired return: ${data.pinCode}`); 309 if (callback) { 310 callback(data) 311 } 312 }) 313 } 314 315 /** 316 * Unsubscribe PinRequired 317 */ 318 unsubscribePinRequired(callback?: (data: { 319 deviceId: string; 320 pinCode: string; 321 }) => void): void { 322 LogUtil.info('bluetooth.unsubscribePinRequired start'); 323 bluetooth.off('pinRequired', (data: { 324 deviceId: string; 325 pinCode: string; 326 }) => { 327 if(data == undefined || !data){ 328 LogUtil.error(`${this.TAG} unsubscribePinRequired->pinRequired error`); 329 return; 330 } 331 LogUtil.info(`${this.TAG} unsubscribePinRequired->pinRequired return: ${data.pinCode}`); 332 if (callback) { 333 callback(data) 334 } 335 }) 336 } 337 338 /** 339 * Set device PairingConfirmation 340 */ 341 setDevicePairingConfirmation(deviceId: string, accept: boolean): boolean { 342 LogUtil.info('bluetooth.setDevicePairingConfirmation start, accept:' + accept); 343 let ret = bluetooth.setDevicePairingConfirmation(deviceId, accept); 344 LogUtil.info('bluetooth.unsubscribePinRequired end, ret: ' + ret); 345 return ret; 346 } 347 348 /** 349 * Subscribe bondStateChange 350 */ 351 subscribeBondStateChange(callback): void { 352 LogUtil.info('bluetooth.subscribeBondStateChange start'); 353 bluetooth.on('bondStateChange', (data) => { 354 LogUtil.info(`${this.TAG} subscribeBondStateChange->bondStateChange data.state:${JSON.stringify(data.state)}`); 355 if (callback) { 356 let result = { 357 deviceId: data.deviceId, 358 bondState: data.state 359 } 360 LogUtil.info(`${this.TAG} subscribeBondStateChange->bondStateChange return:${JSON.stringify(result.bondState)}`); 361 callback(result); 362 } 363 }) 364 } 365 366 /** 367 * Unsubscribe bondStateChange 368 */ 369 unsubscribeBondStateChange(callback?: (data: { 370 deviceId: string; 371 bondState: number; 372 }) => void): void { 373 bluetooth.off('bondStateChange', (data) => { 374 LogUtil.info(`${this.TAG} unsubscribeBondStateChange->bondStateChange start`); 375 if (callback) { 376 let result = { 377 deviceId: data.deviceId, 378 bondState: data.state 379 } 380 LogUtil.info(`${this.TAG} unsubscribeBondStateChange->bondStateChange return:${JSON.stringify(result.bondState)}`); 381 callback(result); 382 } 383 }) 384 } 385 386 /** 387 * Get device name 388 */ 389 getDeviceName(deviceId: string): string { 390 return bluetooth.getRemoteDeviceName(deviceId); 391 } 392 393 /** 394 * Get device type 395 */ 396 getDeviceType(deviceId: string): string { 397 let deviceType = DeviceType.BLUETOOTH; 398 let deviceClass = bluetooth.getRemoteDeviceClass(deviceId); 399 switch (deviceClass.majorClass) { 400 case 0x0100: 401 deviceType = DeviceType.COMPUTER; 402 break; 403 case 0x0400: 404 if (deviceClass.majorMinorClass === 0x0418 || deviceClass.majorMinorClass === 0x0404) { 405 deviceType = DeviceType.HEADPHONE; 406 } 407 break; 408 case 0x0700: 409 if (deviceClass.majorMinorClass === 0x0704) { 410 deviceType = DeviceType.WATCH; 411 } 412 break; 413 case 0x0200: 414 deviceType = DeviceType.PHONE; 415 break; 416 default: 417 deviceType = DeviceType.BLUETOOTH; 418 break; 419 } 420 LogUtil.info('bluetooth.getDeviceType end, return:' + deviceType); 421 return deviceType; 422 } 423 424 /** 425 * Get device state 426 */ 427 getDeviceState(deviceId: string): Array<{ 428 profileId: number; 429 profileConnectionState: number; 430 }> { 431 let result = []; 432 for (let i = 0;i < this.profiles.length; i++) { 433 if (this.profiles[i]) { 434 try { 435 let state = this.profiles[i].getDeviceState(deviceId); 436 result.push({ 437 profileId: i, 438 profileConnectionState: state 439 }); 440 } catch (BusinessError) { 441 LogUtil.error('Bluetooth getDeviceState failed , BusinessError is ' + JSON.stringify(BusinessError)); 442 } 443 } 444 } 445 return result; 446 } 447 448 /** 449 * Unpair device 450 */ 451 unpairDevice(deviceId: string): boolean { 452 return bluetooth.cancelPairedDevice(deviceId); 453 } 454 455 /** 456 * Connect device 457 */ 458 connectDevice(deviceId: string): Array<{ 459 profileId: number; 460 connectRet: boolean; 461 }> { 462 LogUtil.info('bluetooth.connectDevice start'); 463 let result = []; 464 for (let i = 0;i < this.profiles.length; i++) { 465 if (this.profiles[i]) { 466 let profile = this.profiles[i]; 467 let connectRet = true; 468 try { 469 profile.connect(deviceId); 470 } catch (BusinessError) { 471 LogUtil.info(`${this.TAG} connect failed. BusinessError is ` + JSON.stringify(BusinessError)); 472 connectRet = false; 473 } 474 result.push({ 475 profileId: i, 476 connectRet: connectRet 477 }); 478 } 479 } 480 LogUtil.info('bluetooth.connectDevice end, return:' + result); 481 return result; 482 } 483 484 /** 485 * Disconnect device 486 */ 487 disconnectDevice(deviceId: string): Array<{ 488 profileId: number; 489 disconnectRet: boolean; 490 }> { 491 LogUtil.info('bluetooth.disconnectDevice start'); 492 let result = []; 493 for (let i = 0;i < this.profiles.length; i++) { 494 let profile = this.profiles[i]; 495 if (this.profiles[i]) { 496 let profileConnectionState = profile.getDeviceState(deviceId); 497 let disconnectRet = true; 498 LogUtil.info(`${this.TAG} disconnectDevice , connectionState = ${profileConnectionState}`); 499 if (profileConnectionState === 2) { 500 try { 501 profile.disconnect(deviceId); 502 } catch (BusinessError) { 503 LogUtil.info(`${this.TAG} disconnect failed. BusinessError is ` + JSON.stringify(BusinessError)); 504 disconnectRet = false; 505 } 506 } 507 result.push({ 508 profileId: i, 509 disconnectRet: disconnectRet 510 }); 511 } 512 } 513 LogUtil.info('bluetooth.connectDevice end, return:' + result); 514 return result; 515 } 516 517 /** 518 * Subscribe device connection state Change 519 */ 520 subscribeDeviceStateChange(callback: (data: { 521 profileId: number; 522 deviceId: string; 523 profileConnectionState: number; 524 }) => void): void { 525 for (let i = 0;i < this.profiles.length; i++) { 526 if (this.profiles[i]) { 527 let profile = this.profiles[i]; 528 profile.on('connectionStateChange', (data) => { 529 if (callback) { 530 let result = { 531 profileId: i, 532 deviceId: data.deviceId, 533 profileConnectionState: data.state 534 }; 535 LogUtil.info(`${this.TAG} subscribeDeviceStateChange->connectionStateChange, 536 return:${result.profileId} - ${result.profileConnectionState}`); 537 callback(result); 538 } 539 }) 540 } 541 } 542 } 543 544 /** 545 * unsubscribe device connection state Change 546 */ 547 unsubscribeDeviceStateChange(callback?: (data: { 548 profileId: number; 549 deviceId: string; 550 profileConnectionState: number; 551 }) => void): void { 552 for (let i = 0;i < this.profiles.length; i++) { 553 if (this.profiles[i]) { 554 let profile = this.profiles[i]; 555 profile.off('connectionStateChange'); 556 } 557 } 558 } 559} 560 561let bluetoothModel = new BluetoothModel(); 562 563export default bluetoothModel as BluetoothModel;