Skip to content

Commit 90c1778

Browse files
authored
Merge pull request #105 from Resgrid/develop
RR-T40 Moving phone permission check to voice call instead of startup.
2 parents 7b4061f + af8db7e commit 90c1778

File tree

4 files changed

+105
-7
lines changed

4 files changed

+105
-7
lines changed

.agent/rules/rules.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
---
2+
trigger: always_on
3+
---
4+
15
You are an expert in TypeScript, React Native, Expo, and Mobile App Development.
26

37
Code Style and Structure:
@@ -64,3 +68,27 @@ Additional Rules:
6468
- Use `@rnmapbox/maps` for maps, mapping or vehicle navigation
6569
- Use `lucide-react-native` for icons and use those components directly in the markup and don't use the gluestack-ui icon component
6670
- Use ? : for conditional rendering and not &&
71+
72+
73+
Be more strict about planning.
74+
75+
76+
Do not say things or provide incorrect information just to be polite; certainty is required.
77+
78+
79+
When solving problems, always analyze them through first principles thinking. Break every challenge down to its basic, fundamental truths and build your solutions from the ground up rather than relying on analogies or common practices.
80+
81+
82+
When debugging, always investigate whether legacy code or previous implementations are interfering with new logic before assuming the new code is inherently broken.
83+
84+
85+
**Anti-Repetition Protocol**
86+
: If a previously suggested fix is reported as failed, do not attempt to "patch" the broken logic or repeat the same suggestion. Instead, explicitly discard your previous assumptions, re-verify the data flow from first principles, and propose a fundamentally different architectural path. Avoid repetition bias at all costs.
87+
88+
89+
**Token Efficiency Protocol**
90+
: Be extremely concise. Prioritize code and technical facts over conversational filler.
91+
92+
93+
**Pre-Flight Verification**
94+
: Always verify the current state of relevant files, imports, and the specific environment (e.g., Windows paths, Node version) BEFORE proposing a change. The goal is to maximize the success rate of the first attempt.

src/services/callkeep.service.android.ts

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,10 @@ export class CallKeepService {
7474

7575
await RNCallKeep.setup(options);
7676

77-
// On Android, we might need to ask for permissions explicitly if not handled by setup
77+
// Set available for Android 23+
78+
// Note: Phone permissions are now requested on-demand when connecting to a voice call
79+
// to avoid prompting users who don't need voice features
7880
if (Platform.Version >= 23) {
79-
if (Platform.Version >= 30) {
80-
const hasPermission = await PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.READ_PHONE_NUMBERS);
81-
if (!hasPermission) {
82-
await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.READ_PHONE_NUMBERS);
83-
}
84-
}
8581
RNCallKeep.setAvailable(true);
8682
}
8783

@@ -101,6 +97,59 @@ export class CallKeepService {
10197
}
10298
}
10399

100+
/**
101+
* Request phone permissions required for CallKeep to manage calls
102+
* This should be called just before connecting to a voice call
103+
* Returns true if permissions are granted or not required
104+
*/
105+
async requestPhonePermissions(): Promise<boolean> {
106+
if (Platform.OS !== 'android') {
107+
return true;
108+
}
109+
110+
// READ_PHONE_NUMBERS is only required on Android 11+ (API 30+)
111+
if (Platform.Version < 30) {
112+
return true;
113+
}
114+
115+
try {
116+
const hasPermission = await PermissionsAndroid.check(
117+
PermissionsAndroid.PERMISSIONS.READ_PHONE_NUMBERS
118+
);
119+
120+
if (hasPermission) {
121+
logger.debug({
122+
message: 'READ_PHONE_NUMBERS permission already granted',
123+
});
124+
return true;
125+
}
126+
127+
const result = await PermissionsAndroid.request(
128+
PermissionsAndroid.PERMISSIONS.READ_PHONE_NUMBERS,
129+
{
130+
title: 'Phone Permission Required',
131+
message: 'This app needs phone access to manage voice calls with your headset',
132+
buttonPositive: 'Grant',
133+
buttonNegative: 'Deny',
134+
}
135+
);
136+
137+
const granted = result === PermissionsAndroid.RESULTS.GRANTED;
138+
logger.info({
139+
message: 'READ_PHONE_NUMBERS permission request result',
140+
context: { granted, result },
141+
});
142+
143+
return granted;
144+
} catch (error) {
145+
logger.error({
146+
message: 'Failed to request phone permissions',
147+
context: { error },
148+
});
149+
return false;
150+
}
151+
}
152+
104153
/**
105154
* Start a CallKit call to keep the app alive in the background
106155
* This should be called when connecting to a LiveKit room

src/services/callkeep.service.ios.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ export class CallKeepService {
9898
}
9999
}
100100

101+
/**
102+
* Request phone permissions (iOS implementation - no-op)
103+
* This permission is only required on Android for CallKeep headset controls
104+
* On iOS, we always return true as no additional permissions are needed
105+
*/
106+
async requestPhonePermissions(): Promise<boolean> {
107+
// iOS does not require READ_PHONE_NUMBERS permission
108+
return true;
109+
}
110+
101111
/**
102112
* Start a CallKit call to keep the app alive in the background
103113
* This should be called when connecting to a LiveKit room

src/stores/app/livekit-store.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,17 @@ export const useLiveKitStore = create<LiveKitState>((set, get) => ({
340340

341341
// Start CallKeep call (iOS & Android)
342342
if (Platform.OS !== 'web') {
343+
// Request phone permissions for CallKeep headset controls (Android only)
344+
if (Platform.OS === 'android') {
345+
const hasPhonePermission = await callKeepService.requestPhonePermissions();
346+
if (!hasPhonePermission) {
347+
logger.warn({
348+
message: 'Phone permission not granted - headset controls may not work properly',
349+
});
350+
// Don't block connection - continue without phone permission
351+
}
352+
}
353+
343354
// Using a generic handle or room name
344355
const roomName = roomInfo?.Name || 'Voice Channel';
345356
callKeepService

0 commit comments

Comments
 (0)