• 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';
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;