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