Skip to content

Commit 78a491c

Browse files
authored
Merge pull request #149 from Resgrid/develop
Develop
2 parents 6051adc + 1546229 commit 78a491c

23 files changed

+2598
-1432
lines changed

.DS_Store

0 Bytes
Binary file not shown.

__mocks__/expo-audio.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Mock for expo-audio to understand the PermissionStatus structure
2+
export const getRecordingPermissionsAsync = jest.fn();
3+
export const requestRecordingPermissionsAsync = jest.fn();
4+
5+
// Default mock implementation
6+
getRecordingPermissionsAsync.mockResolvedValue({
7+
granted: false,
8+
canAskAgain: true,
9+
expires: 'never',
10+
status: 'undetermined',
11+
});
12+
13+
requestRecordingPermissionsAsync.mockResolvedValue({
14+
granted: true,
15+
canAskAgain: true,
16+
expires: 'never',
17+
status: 'granted',
18+
});
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Mock for react-native-ble-manager
2+
export type BleState = 'on' | 'off' | 'turning_on' | 'turning_off' | 'unsupported' | 'unknown';
3+
4+
export interface Peripheral {
5+
id: string;
6+
name?: string;
7+
rssi?: number;
8+
advertising?: {
9+
isConnectable?: boolean;
10+
localName?: string;
11+
manufacturerData?: any;
12+
serviceUUIDs?: string[];
13+
txPowerLevel?: number;
14+
};
15+
}
16+
17+
export interface BleManagerDidUpdateValueForCharacteristicEvent {
18+
peripheral: string;
19+
characteristic: string;
20+
service: string;
21+
value: number[];
22+
}
23+
24+
const mockPeripherals: Peripheral[] = [];
25+
let mockState: BleState = 'on';
26+
let mockIsScanning = false;
27+
28+
const BleManager = {
29+
start: jest.fn().mockResolvedValue(undefined),
30+
31+
checkState: jest.fn().mockImplementation(() => Promise.resolve(mockState)),
32+
33+
scan: jest.fn().mockImplementation((serviceUUIDs: string[], duration: number, allowDuplicates: boolean = false) => {
34+
mockIsScanning = true;
35+
// Simulate scanning timeout
36+
setTimeout(() => {
37+
mockIsScanning = false;
38+
}, duration * 1000);
39+
return Promise.resolve();
40+
}),
41+
42+
stopScan: jest.fn().mockImplementation(() => {
43+
mockIsScanning = false;
44+
return Promise.resolve();
45+
}),
46+
47+
connect: jest.fn().mockResolvedValue(undefined),
48+
49+
disconnect: jest.fn().mockResolvedValue(undefined),
50+
51+
retrieveServices: jest.fn().mockResolvedValue(undefined),
52+
53+
startNotification: jest.fn().mockResolvedValue(undefined),
54+
55+
stopNotification: jest.fn().mockResolvedValue(undefined),
56+
57+
getConnectedPeripherals: jest.fn().mockResolvedValue([]),
58+
59+
getDiscoveredPeripherals: jest.fn().mockResolvedValue(mockPeripherals),
60+
61+
isPeripheralConnected: jest.fn().mockResolvedValue(false),
62+
63+
// Mock utilities for testing
64+
setMockState: (state: BleState) => {
65+
mockState = state;
66+
},
67+
68+
addMockPeripheral: (peripheral: Peripheral) => {
69+
mockPeripherals.push(peripheral);
70+
},
71+
72+
clearMockPeripherals: () => {
73+
mockPeripherals.length = 0;
74+
},
75+
76+
getMockPeripherals: () => [...mockPeripherals],
77+
78+
isMockScanning: () => mockIsScanning,
79+
};
80+
81+
// Set up as any for easier mocking
82+
(BleManager as any).setMockState = BleManager.setMockState;
83+
(BleManager as any).addMockPeripheral = BleManager.addMockPeripheral;
84+
(BleManager as any).clearMockPeripherals = BleManager.clearMockPeripherals;
85+
(BleManager as any).getMockPeripherals = BleManager.getMockPeripherals;
86+
(BleManager as any).isMockScanning = BleManager.isMockScanning;
87+
88+
export default BleManager;

app.config.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
4444
bundleIdentifier: Env.BUNDLE_ID,
4545
requireFullScreen: true,
4646
infoPlist: {
47-
UIBackgroundModes: ['remote-notification', 'audio'],
47+
UIBackgroundModes: ['remote-notification', 'audio', 'bluetooth-central'],
4848
ITSAppUsesNonExemptEncryption: false,
49+
NSBluetoothAlwaysUsageDescription: 'Allow Resgrid Unit to connect to bluetooth devices for PTT.',
4950
},
5051
},
5152
experiments: {
@@ -234,14 +235,6 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
234235
url: 'https://sentry.resgrid.net/',
235236
},
236237
],
237-
[
238-
'react-native-ble-plx',
239-
{
240-
isBackgroundEnabled: true,
241-
modes: ['peripheral', 'central'],
242-
bluetoothAlwaysPermission: 'Allow Resgrid Unit to connect to bluetooth devices for PTT.',
243-
},
244-
],
245238
[
246239
'expo-navigation-bar',
247240
{
@@ -250,7 +243,13 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
250243
behavior: 'inset-touch',
251244
},
252245
],
253-
'expo-audio',
246+
[
247+
'expo-audio',
248+
{
249+
microphonePermission: 'Allow Resgrid Unit to access the microphone for audio input used in PTT and calls.',
250+
},
251+
],
252+
'react-native-ble-manager',
254253
'@livekit/react-native-expo-plugin',
255254
'@config-plugins/react-native-webrtc',
256255
'./customGradle.plugin.js',
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Bluetooth Device Selection Dialog Migration to react-native-ble-manager
2+
3+
## Overview
4+
5+
The Bluetooth device selection dialog has been updated to support the migration from `react-native-ble-plx` to `react-native-ble-manager` in the bluetooth audio service.
6+
7+
## Key Changes Made
8+
9+
### 1. Enhanced Error Handling
10+
- **Scan Error Recovery**: Added reset of `hasScanned` state on scan errors to allow retry
11+
- **Connection Error Display**: Added display of connection errors from the bluetooth store
12+
- **Bluetooth State Handling**: Improved bluetooth state warnings with specific messages for different states
13+
14+
### 2. Auto-Connect Functionality
15+
- **Smart Device Selection**: When a device is selected as preferred, the dialog now attempts to automatically connect to it if not already connected
16+
- **Non-blocking Connection**: Connection failures during selection don't block the preference setting - they're logged as warnings
17+
18+
### 3. Enhanced Device Information Display
19+
- **Audio Capability Badge**: Added display of `hasAudioCapability` property for devices
20+
- **Connection Status**: Enhanced display of connection status in the selected device section
21+
- **Better Device Metadata**: Improved display of device capabilities and connection state
22+
23+
### 4. Improved Scanning Management
24+
- **Automatic Scan Cleanup**: Added cleanup to stop scanning when dialog closes or component unmounts
25+
- **Scan State Management**: Better handling of scan state to prevent memory leaks
26+
27+
### 5. Updated Dependencies and Imports
28+
- **Store Compatibility**: Updated to use `connectionError` from the bluetooth store
29+
- **Type Safety**: Maintained compatibility with the new `BluetoothAudioDevice` interface from react-native-ble-manager
30+
31+
### 6. Testing Infrastructure
32+
- **Mock Creation**: Created new mock for `react-native-ble-manager` to replace old `react-native-ble-plx` mock
33+
- **Icon Mocking**: Added proper mocking for lucide icons to avoid SVG-related test failures
34+
- **Comprehensive Tests**: Added tests for new functionality including error states and auto-connect behavior
35+
36+
## Compatibility Notes
37+
38+
### What Stayed the Same
39+
- **Component Interface**: The component props and public API remain unchanged
40+
- **UI/UX**: The visual design and user interaction patterns are maintained
41+
- **Core Functionality**: Device selection and preference setting work exactly as before
42+
43+
### What Changed Internally
44+
- **Service Integration**: Now properly integrates with the migrated bluetooth service using react-native-ble-manager
45+
- **Error Handling**: More robust error handling and user feedback
46+
- **State Management**: Better state cleanup and scanning lifecycle management
47+
48+
## Migration Benefits
49+
50+
1. **Better Reliability**: Improved error handling and state management
51+
2. **Enhanced UX**: Auto-connect functionality and better status display
52+
3. **Improved Performance**: Better scan lifecycle management prevents memory leaks
53+
4. **Future-Proof**: Compatible with the new react-native-ble-manager architecture
54+
55+
## Technical Details
56+
57+
### New Properties Used
58+
- `hasAudioCapability`: Displayed as a badge for audio-capable devices
59+
- `connectionError`: Shown in error display section
60+
- Enhanced bluetooth state handling with specific error messages
61+
62+
### Enhanced Functionality
63+
- **Auto-connect on selection**: Attempts to connect when device is selected as preferred
64+
- **Scan cleanup**: Properly stops scanning when dialog closes
65+
- **Error recovery**: Better error handling with retry capabilities
66+
67+
## Testing
68+
- Created comprehensive test suite covering all new functionality
69+
- Added mocks for react-native-ble-manager compatibility
70+
- Tests cover error states, auto-connect behavior, and scan management
71+
72+
The updated dialog is now fully compatible with the react-native-ble-manager migration while providing enhanced functionality and better user experience.

package.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@
118118
"expo-linking": "~7.0.3",
119119
"expo-localization": "~16.0.0",
120120
"expo-location": "~18.0.10",
121-
"expo-modules-core": "~2.2.3",
122121
"expo-navigation-bar": "~4.0.9",
123122
"expo-notifications": "~0.29.14",
124123
"expo-router": "~4.0.21",
@@ -137,20 +136,19 @@
137136
"moti": "~0.29.0",
138137
"nativewind": "~4.1.21",
139138
"react": "18.3.1",
140-
"react-dom": "^19.1.0",
139+
"react-dom": "18.3.1",
141140
"react-error-boundary": "~4.0.13",
142141
"react-hook-form": "~7.53.0",
143142
"react-i18next": "~15.0.1",
144143
"react-native": "0.76.9",
145144
"react-native-base64": "~0.2.1",
146-
"react-native-ble-plx": "^3.5.0",
145+
"react-native-ble-manager": "^12.1.5",
147146
"react-native-edge-to-edge": "~1.1.2",
148147
"react-native-flash-message": "~0.4.2",
149148
"react-native-gesture-handler": "~2.20.2",
150149
"react-native-keyboard-controller": "~1.15.2",
151150
"react-native-logs": "~5.3.0",
152151
"react-native-mmkv": "~3.1.0",
153-
"react-native-permissions": "^5.4.1",
154152
"react-native-reanimated": "~3.16.1",
155153
"react-native-restart": "0.0.27",
156154
"react-native-safe-area-context": "4.12.0",

0 commit comments

Comments
 (0)