Skip to Content
ReferencePermissions

Permissions & manifest

Runtime permissions

PermissionWhen requestedIf denied
CAMERAFirst launch / before first callNo video; the app toasts and stays on Home
RECORD_AUDIOSame request as cameraNo calls at all - both are required together
POST_NOTIFICATIONS (API 33+)Before starting a callCall still works; no ongoing-call notification

MainActivity builds the WebRtcClient after the camera + mic grant so the Home self-preview lights up without an app restart.

Declared permissions

<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
PermissionUsed for
MODIFY_AUDIO_SETTINGSCallAudioRouter - earpiece / speaker / routing
BLUETOOTH / BLUETOOTH_CONNECTBT headset detection & routing
WAKE_LOCKkeepScreenOn during a call (via a Compose DisposableEffect, not a manual lock)
ACCESS_NETWORK_STATEWebRTC’s NetworkMonitor - detects Wi-Fi ↔ cellular changes for ICE
FOREGROUND_SERVICE_*The typed FGS - see below

Foreground service

<service android:name=".service.CallForegroundService" android:foregroundServiceType="camera|microphone|mediaProjection" android:exported="false" />
  • Started when a call connects; stopped on hang-up.
  • Carries a CallStyle notification with a Hang Up action.
  • The mediaProjection type is required before MediaProjectionManager.getMediaProjection() on Android 14+ - CallForegroundService.onMediaProjectionReady is the callback the screen-share flow waits for.
  • onStartCommand returns START_NOT_STICKY - a killed process means the call is over, not something to resurrect.

Activity declaration

<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTask" android:supportsPictureInPicture="true" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboardHidden|uiMode|density|fontScale" android:windowSoftInputMode="adjustResize">
AttributeWhy
launchMode="singleTask"Re-launching from the launcher while in PiP re-enters the existing instance instead of stacking a second one
supportsPictureInPicture="true"PiP on onUserLeaveHint
configChanges=…uiMode|density|fontScale…A rotation / dark-mode / font-scale change doesn’t recreate the Activity mid-call and tear down the PeerConnection

Features

<uses-feature android:name="android.hardware.camera" android:required="false" /> <uses-feature android:name="android.hardware.microphone" android:required="false" />

Both required="false" so the app installs on devices without a camera (it just can’t make video calls).

usesCleartextTraffic

android:usesCleartextTraffic="true" is set so a self-hoster can point the app at a plain ws:// server on a trusted LAN during testing. Production deployments use wss://.