call-screen
v0.0.7
Published
Capacitor plugin for full-screen call UI with Accept/Reject buttons, OneSignal integration, and cross-platform support
Maintainers
Readme
Call Screen Plugin
A Capacitor plugin for full-screen call UI with Accept/Reject buttons, OneSignal integration, and cross-platform support.
Features
- ✅ Full-screen call UI with accept/reject buttons
- ✅ Custom ringtone and vibration
- ✅ Works when app is closed (via OneSignal)
- ✅ Shows over lock screen
- ✅ Foreground service for reliable operation
- ✅ Cross-platform support (Android, iOS, Web)
- ✅ OneSignal integration for push notifications
- ✅ Room name support for call context
- ✅ Call action callbacks (accepted/rejected events)
Installation
npm install call-screenSetup
1. Install OneSignal Plugin
npm install onesignal-cordova-plugin2. Initialize OneSignal in your app
import OneSignal from 'onesignal-cordova-plugin';
import { CallScreen } from 'call-screen';
// Initialize OneSignal
OneSignal.setAppId('YOUR_ONESIGNAL_APP_ID');
// Request notification permission
OneSignal.promptForPushNotificationsWithUserResponse(response => {
console.log('Prompt response:', response);
});
// Handle notifications when app is in foreground
OneSignal.setNotificationWillShowInForegroundHandler(notificationReceivedEvent => {
const notification = notificationReceivedEvent.getNotification();
const data = notification.additionalData;
// Check if this is an incoming call notification
if (data && data.notification_type === 'incoming_call') {
// Prevent OneSignal from showing default notification
notificationReceivedEvent.complete(null);
// Handle the call
handleIncomingCall(data);
} else {
// Let OneSignal show the default notification
notificationReceivedEvent.complete(notification);
}
});
// Handle notification clicks
OneSignal.setNotificationOpenedHandler(notification => {
const data = notification.notification.additionalData;
if (data && data.notification_type === 'incoming_call') {
handleIncomingCall(data);
}
});
// Handle incoming call
async function handleIncomingCall(data: any) {
try {
await CallScreen.handleIncomingCall({
username: data.username || 'Unknown Caller',
callId: data.call_id || Date.now().toString(),
roomName: data.room_name || ''
});
} catch (error) {
console.error('Error handling incoming call:', error);
}
}Usage
Show Call Screen Manually
import { CallScreen } from 'call-screen';
// Show call screen with room name
await CallScreen.showCallScreen({
username: 'John Doe',
callId: 'call_123',
roomName: 'Meeting Room A'
});Handle Incoming Call
// This is called when a OneSignal notification is received
await CallScreen.handleIncomingCall({
username: 'Alice Smith',
callId: 'call_456',
roomName: 'Conference Room B'
});Listen for Call Actions
// Listen for call acceptance/rejection
const callActionListener = await CallScreen.addListener('callAction', (event) => {
console.log('Call action:', event.action); // 'accepted' or 'rejected'
console.log('Caller:', event.username);
console.log('Call ID:', event.callId);
console.log('Room:', event.roomName); // optional
if (event.action === 'accepted') {
// Handle accepted call - connect to WebRTC, open call UI, etc.
connectToCall(event.username, event.callId, event.roomName);
} else {
// Handle rejected call - notify server, update UI, etc.
notifyCallRejected(event.username, event.callId, event.roomName);
}
});
// Clean up listener when done
await CallScreen.removeAllListeners('callAction');Stop Active Call
await CallScreen.stopCall();Check Call Status
const result = await CallScreen.isCallActive();
console.log('Call active:', result.isActive);OneSignal Integration
Notification Payload Format
Send OneSignal notifications with this format:
{
"app_id": "YOUR_ONESIGNAL_APP_ID",
"included_segments": ["All"],
"data": {
"notification_type": "incoming_call",
"username": "John Doe",
"call_id": "call_123",
"room_name": "Meeting Room A",
"is_call": true,
"call_type": "incoming"
},
"contents": {
"en": "Incoming call from John Doe"
},
"headings": {
"en": "Incoming Call"
}
}Testing Scenarios
- App in Foreground: Call screen appears immediately
- App in Background: Call screen appears over lock screen
- App Closed: Call screen appears and ringtone plays
- Device Locked: Call screen appears over lock screen
Android Permissions
The plugin automatically requests these permissions:
FOREGROUND_SERVICE- For reliable call serviceWAKE_LOCK- To wake device for callsDISABLE_KEYGUARD- To show over lock screenVIBRATE- For call vibrationMODIFY_AUDIO_SETTINGS- For ringtone controlACCESS_NOTIFICATION_POLICY- To override Do Not DisturbSYSTEM_ALERT_WINDOW- To show over other appsUSE_FULL_SCREEN_INTENT- For full-screen call UIRECEIVE_BOOT_COMPLETED- For app closed statePOST_NOTIFICATIONS- For Android 13+ notificationsINTERNET- For network operationsACCESS_NETWORK_STATE- For network status
Troubleshooting
Call screen doesn't appear when app is closed
- Verify OneSignal integration is properly set up
- Check notification payload format
- Ensure
CallScreen.handleIncomingCall()is called - Check device battery optimization settings
No ringtone sound
- Check device volume settings
- Verify Do Not Disturb mode is not blocking audio
- Grant notification policy access if prompted
- Check that ringtone.mp3 exists in res/raw folder
Call screen appears but buttons don't work
- Check service binding in CallScreenActivity
- Verify no crash logs in Android Studio
- Ensure proper activity configuration
Debugging
Monitor logs with:
adb logcat | grep -E "(CallNotification|CallScreen|OneSignal)"Expected log output:
CallNotificationExtender: === handleNotification ===
CallNotificationService: === CallNotificationService onStartCommand called ===
CallNotificationService: Ringtone started successfully using custom ringtone from raw folder
CallScreenActivity: === CallScreenActivity onCreate ===API Reference
CallScreen.showCallScreen(options)
Shows the call screen manually.
Parameters:
options.username(string): Name of the calleroptions.callId(string, optional): Unique call identifieroptions.roomName(string, optional): Room name for call context
CallScreen.handleIncomingCall(options)
Handles an incoming call from OneSignal notification.
Parameters:
options.username(string): Name of the calleroptions.callId(string, optional): Unique call identifieroptions.roomName(string, optional): Room name for call context
CallScreen.stopCall()
Stops the active call and closes the call screen.
CallScreen.isCallActive()
Checks if there's an active call.
Returns: Promise<{ isActive: boolean }>
CallScreen.addListener(eventName, listenerFunc)
Listen for call action events (accepted/rejected).
Parameters:
eventName(string): Must be 'callAction'listenerFunc(function): Callback function that receives CallActionEvent
Returns: Promise
CallScreen.removeAllListeners(eventName)
Remove all listeners for a specific event.
Parameters:
eventName(string): Event name to remove listeners for
CallActionEvent Interface
interface CallActionEvent {
action: 'accepted' | 'rejected';
username: string;
callId: string;
roomName?: string;
}Examples
See onesignal-integration-example.ts for a complete integration example.
Complete Call Management Example
import { CallScreen, CallActionEvent } from 'call-screen';
class CallManager {
private callActionListener: any;
constructor() {
this.setupCallListener();
}
private async setupCallListener() {
this.callActionListener = await CallScreen.addListener('callAction', (event: CallActionEvent) => {
if (event.action === 'accepted') {
this.handleCallAccepted(event);
} else {
this.handleCallRejected(event);
}
});
}
private handleCallAccepted(event: CallActionEvent) {
console.log(`Call accepted from ${event.username} in room: ${event.roomName || 'No room'}`);
// Connect to WebRTC, open call UI, etc.
}
private handleCallRejected(event: CallActionEvent) {
console.log(`Call rejected from ${event.username} in room: ${event.roomName || 'No room'}`);
// Notify server, update UI, etc.
}
async showIncomingCall(username: string, callId: string, roomName?: string) {
await CallScreen.handleIncomingCall({ username, callId, roomName });
}
async cleanup() {
if (this.callActionListener) {
await CallScreen.removeAllListeners('callAction');
}
}
}License
MIT
