• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;