Add wake lock and device keepalive for reliable mobile calls

Prevents screen sleep during calls and auto-reconnects the Twilio device
after app backgrounding. JS handles Screen Wake Lock API and 30s keepalive
polling; Flutter coordinates via WakelockPlus and synthetic visibilitychange
events on app resume.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude
2026-04-27 05:52:39 -07:00
parent fe8ddd51bb
commit 3407f4c705
5 changed files with 197 additions and 34 deletions

View File

@@ -110,6 +110,8 @@ var twpTwilioEdge = window.twpConfig.twilioEdge;
var serviceWorkerRegistration = null;
var currentCallDirection = null;
var callHistory = [];
var wakeLock = null;
var deviceKeepaliveTimer = null;
// ============================================================
// AudioContext & Ringtone
@@ -193,13 +195,79 @@ var twpTwilioEdge = window.twpConfig.twilioEdge;
}
}
// ============================================================
// Screen Wake Lock
// ============================================================
async function requestWakeLock() {
if (!('wakeLock' in navigator)) return;
try {
wakeLock = await navigator.wakeLock.request('screen');
console.log('TWP: Wake lock acquired');
wakeLock.addEventListener('release', function() {
console.log('TWP: Wake lock released');
wakeLock = null;
});
} catch (e) {
console.warn('TWP: Wake lock request failed:', e.message);
}
}
function releaseWakeLock() {
if (wakeLock) {
wakeLock.release().catch(function() {});
wakeLock = null;
}
}
// ============================================================
// Device Keepalive Monitor
// ============================================================
function startDeviceKeepalive() {
stopDeviceKeepalive();
deviceKeepaliveTimer = setInterval(function() {
if (device && deviceConnectionState !== 'connected' && !currentCall) {
console.log('TWP: Keepalive — device disconnected, re-registering');
device.register().catch(function(e) {
console.warn('TWP: Keepalive re-register failed:', e.message);
});
}
}, 30000);
}
function stopDeviceKeepalive() {
if (deviceKeepaliveTimer) {
clearInterval(deviceKeepaliveTimer);
deviceKeepaliveTimer = null;
}
}
// ============================================================
// Page Visibility
// ============================================================
function setupPageVisibility() {
document.addEventListener('visibilitychange', function() {
isPageVisible = !document.hidden;
if (isPageVisible && audioContext) initializeAudioContext();
if (isPageVisible) {
console.log('TWP: Page visible — checking connections');
// Resume audio
if (audioContext) initializeAudioContext();
// Re-request wake lock (auto-released when tab hidden)
requestWakeLock();
// Check token expiry — refresh if expired or within 2 minutes
if (tokenExpiry && (Date.now() > tokenExpiry - 2 * 60 * 1000)) {
console.log('TWP: Token expired or expiring soon, refreshing');
refreshToken();
}
// Check device registration
if (device && deviceConnectionState !== 'connected' && !currentCall) {
console.log('TWP: Device disconnected, re-registering');
device.register().catch(function(e) {
console.warn('TWP: Visibility re-register failed:', e.message);
});
}
} else {
console.log('TWP: Page hidden — wake lock auto-released by browser');
}
});
}
@@ -352,6 +420,8 @@ var twpTwilioEdge = window.twpConfig.twilioEdge;
device.on('tokenWillExpire', function() { refreshToken(); });
await device.register();
requestWakeLock();
startDeviceKeepalive();
} catch (error) {
showError('Failed to setup device: ' + error.message);
}
@@ -363,6 +433,7 @@ var twpTwilioEdge = window.twpConfig.twilioEdge;
function setupCallHandlers(call) {
call.on('accept', function() {
stopRingtone();
requestWakeLock();
$('#phone-status').text('Connected').css('color', 'var(--accent)');
$('#call-btn').hide();
$('#answer-btn').hide();
@@ -1041,6 +1112,8 @@ var twpTwilioEdge = window.twpConfig.twilioEdge;
// ============================================================
$(window).on('beforeunload', function() {
if (tokenRefreshTimer) clearTimeout(tokenRefreshTimer);
releaseWakeLock();
stopDeviceKeepalive();
if (device) device.destroy();
});