53 lines
2.2 KiB
TypeScript
53 lines
2.2 KiB
TypeScript
// Keep an Android foreground service alive while a DM call is actively joined.
|
|
//
|
|
// Lifecycle is keyed to the widget's JoinCall signal (via useCallJoined), not
|
|
// the mere presence of callEmbedAtom. Rationale:
|
|
//
|
|
// 1. RECORD_AUDIO runtime grant. By the time JoinCall fires, Element Call
|
|
// inside the iframe has already called getUserMedia, which prompted the
|
|
// OS permission dialog (if needed) and user granted. Starting the FGS
|
|
// earlier (during `preparing`, before getUserMedia) means RECORD_AUDIO
|
|
// may not be granted yet — and on API 34+ startForeground with
|
|
// TYPE_MICROPHONE throws SecurityException without it, while a
|
|
// fallback to TYPE_NONE is not a valid subset of the manifest-declared
|
|
// `microphone` service type. Gating on joined sidesteps the whole
|
|
// fallback question.
|
|
//
|
|
// 2. No ghost notification during preparingError. If the widget fails to
|
|
// load, JoinCall never fires, the service never starts, nothing to
|
|
// clean up.
|
|
//
|
|
// Tradeoff: a tiny (1-3s) window between embed creation and JoinCall has no
|
|
// retention. The call isn't actually live in that window — media hasn't
|
|
// started — so lock-screen there is a non-event; user can retry.
|
|
//
|
|
// Android-only.
|
|
|
|
import { useEffect } from 'react';
|
|
import { useAtomValue } from 'jotai';
|
|
import { callEmbedAtom } from '../state/callEmbed';
|
|
import { callForegroundService } from '../plugins/call/callForegroundService';
|
|
import { useCallJoined } from './useCallEmbed';
|
|
import { isAndroidPlatform } from '../utils/capacitor';
|
|
|
|
export const useAndroidCallForegroundSync = (): void => {
|
|
const callEmbed = useAtomValue(callEmbedAtom);
|
|
const joined = useCallJoined(callEmbed);
|
|
|
|
useEffect(() => {
|
|
if (!isAndroidPlatform()) return undefined;
|
|
if (!joined) return undefined;
|
|
|
|
callForegroundService.start({ title: 'Активный звонок' }).catch((err: unknown) => {
|
|
// eslint-disable-next-line no-console
|
|
console.warn('[call-fgs] start failed', err);
|
|
});
|
|
|
|
return () => {
|
|
callForegroundService.stop().catch((err: unknown) => {
|
|
// eslint-disable-next-line no-console
|
|
console.warn('[call-fgs] stop failed', err);
|
|
});
|
|
};
|
|
}, [joined]);
|
|
};
|