feat: incoming call notification works in any scenario
All checks were successful
/ mirror (push) Successful in 4s
All checks were successful
/ mirror (push) Successful in 4s
This commit is contained in:
parent
ffbd7bdfaa
commit
5820111341
@ -6,11 +6,8 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.provider.CallLog
|
import android.provider.CallLog
|
||||||
import android.telecom.TelecomManager
|
import android.telecom.TelecomManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
@ -29,18 +26,22 @@ class MainActivity : FlutterActivity() {
|
|||||||
private val TAG = "MainActivity"
|
private val TAG = "MainActivity"
|
||||||
private val REQUEST_CODE_SET_DEFAULT_DIALER = 1001
|
private val REQUEST_CODE_SET_DEFAULT_DIALER = 1001
|
||||||
private val REQUEST_CODE_CALL_LOG_PERMISSION = 1002
|
private val REQUEST_CODE_CALL_LOG_PERMISSION = 1002
|
||||||
private var pendingIncomingCall: Pair<String?, Boolean>? = null // Store incoming call data
|
private var pendingIncomingCall: Pair<String?, Boolean>? = null
|
||||||
|
private var wasPhoneLocked: Boolean = false
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
Log.d(TAG, "onCreate started")
|
Log.d(TAG, "onCreate started")
|
||||||
Log.d(TAG, "Waiting for Flutter to signal permissions")
|
wasPhoneLocked = intent.getBooleanExtra("wasPhoneLocked", false)
|
||||||
|
Log.d(TAG, "Was phone locked at start: $wasPhoneLocked")
|
||||||
handleIncomingCallIntent(intent)
|
handleIncomingCallIntent(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent) {
|
override fun onNewIntent(intent: Intent) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
setIntent(intent)
|
setIntent(intent)
|
||||||
|
wasPhoneLocked = intent.getBooleanExtra("wasPhoneLocked", false)
|
||||||
|
Log.d(TAG, "onNewIntent, wasPhoneLocked: $wasPhoneLocked")
|
||||||
handleIncomingCallIntent(intent)
|
handleIncomingCallIntent(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,13 +55,22 @@ class MainActivity : FlutterActivity() {
|
|||||||
when (call.method) {
|
when (call.method) {
|
||||||
"permissionsGranted" -> {
|
"permissionsGranted" -> {
|
||||||
Log.d(TAG, "Received permissionsGranted from Flutter")
|
Log.d(TAG, "Received permissionsGranted from Flutter")
|
||||||
|
pendingIncomingCall?.let { (phoneNumber, showScreen) ->
|
||||||
|
if (showScreen) {
|
||||||
|
MyInCallService.channel?.invokeMethod("incomingCallFromNotification", mapOf(
|
||||||
|
"phoneNumber" to phoneNumber,
|
||||||
|
"wasPhoneLocked" to wasPhoneLocked
|
||||||
|
))
|
||||||
|
pendingIncomingCall = null
|
||||||
|
}
|
||||||
|
}
|
||||||
checkAndRequestDefaultDialer()
|
checkAndRequestDefaultDialer()
|
||||||
result.success(true)
|
result.success(true)
|
||||||
}
|
}
|
||||||
"makeGsmCall" -> {
|
"makeGsmCall" -> {
|
||||||
val phoneNumber = call.argument<String>("phoneNumber")
|
val phoneNumber = call.argument<String>("phoneNumber")
|
||||||
if (phoneNumber != null) {
|
if (phoneNumber != null) {
|
||||||
val success = CallService.makeGsmCall(this, phoneNumber) // Use CallService
|
val success = CallService.makeGsmCall(this, phoneNumber)
|
||||||
if (success) {
|
if (success) {
|
||||||
result.success(mapOf("status" to "calling", "phoneNumber" to phoneNumber))
|
result.success(mapOf("status" to "calling", "phoneNumber" to phoneNumber))
|
||||||
} else {
|
} else {
|
||||||
@ -75,12 +85,17 @@ class MainActivity : FlutterActivity() {
|
|||||||
it.disconnect()
|
it.disconnect()
|
||||||
Log.d(TAG, "Call disconnected")
|
Log.d(TAG, "Call disconnected")
|
||||||
MyInCallService.channel?.invokeMethod("callEnded", mapOf(
|
MyInCallService.channel?.invokeMethod("callEnded", mapOf(
|
||||||
"callId" to it.details.handle.toString()
|
"callId" to it.details.handle.toString(),
|
||||||
|
"wasPhoneLocked" to wasPhoneLocked
|
||||||
))
|
))
|
||||||
true
|
true
|
||||||
} ?: false
|
} ?: false
|
||||||
if (success) {
|
if (success) {
|
||||||
result.success(mapOf("status" to "ended"))
|
result.success(mapOf("status" to "ended"))
|
||||||
|
if (wasPhoneLocked) {
|
||||||
|
Log.d(TAG, "Finishing and removing task after hangup, phone was locked")
|
||||||
|
finishAndRemoveTask()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "No active call to hang up")
|
Log.w(TAG, "No active call to hang up")
|
||||||
result.error("HANGUP_FAILED", "No active call to hang up", null)
|
result.error("HANGUP_FAILED", "No active call to hang up", null)
|
||||||
@ -99,15 +114,11 @@ class MainActivity : FlutterActivity() {
|
|||||||
result.error("ANSWER_FAILED", "No active call to answer", null)
|
result.error("ANSWER_FAILED", "No active call to answer", null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"flutterReady" -> { // New method to signal Flutter is initialized
|
"callEndedFromFlutter" -> {
|
||||||
Log.d(TAG, "Flutter is ready")
|
Log.d(TAG, "Call ended from Flutter, wasPhoneLocked: $wasPhoneLocked")
|
||||||
pendingIncomingCall?.let { (phoneNumber, showScreen) ->
|
if (wasPhoneLocked) {
|
||||||
if (showScreen) {
|
finishAndRemoveTask()
|
||||||
MyInCallService.channel?.invokeMethod("incomingCallFromNotification", mapOf(
|
Log.d(TAG, "Finishing and removing task after call ended, phone was locked")
|
||||||
"phoneNumber" to phoneNumber
|
|
||||||
))
|
|
||||||
pendingIncomingCall = null // Clear after handling
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
result.success(true)
|
result.success(true)
|
||||||
}
|
}
|
||||||
@ -148,8 +159,6 @@ class MainActivity : FlutterActivity() {
|
|||||||
val intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER)
|
val intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER)
|
||||||
startActivityForResult(intent, REQUEST_CODE_SET_DEFAULT_DIALER)
|
startActivityForResult(intent, REQUEST_CODE_SET_DEFAULT_DIALER)
|
||||||
Log.d(TAG, "Launched RoleManager intent for default dialer on API 29+")
|
Log.d(TAG, "Launched RoleManager intent for default dialer on API 29+")
|
||||||
} else {
|
|
||||||
Log.d(TAG, "RoleManager: Available=${roleManager.isRoleAvailable(RoleManager.ROLE_DIALER)}, Held=${roleManager.isRoleHeld(RoleManager.ROLE_DIALER)}")
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val intent = Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER)
|
val intent = Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER)
|
||||||
@ -228,14 +237,14 @@ class MainActivity : FlutterActivity() {
|
|||||||
if (it.getBooleanExtra("isIncomingCall", false)) {
|
if (it.getBooleanExtra("isIncomingCall", false)) {
|
||||||
val phoneNumber = it.getStringExtra("phoneNumber")
|
val phoneNumber = it.getStringExtra("phoneNumber")
|
||||||
val showScreen = it.getBooleanExtra("showIncomingCallScreen", false)
|
val showScreen = it.getBooleanExtra("showIncomingCallScreen", false)
|
||||||
Log.d(TAG, "Received incoming call intent for $phoneNumber, showScreen=$showScreen")
|
Log.d(TAG, "Received incoming call intent for $phoneNumber, showScreen=$showScreen, wasPhoneLocked=$wasPhoneLocked")
|
||||||
if (showScreen) {
|
if (showScreen) {
|
||||||
if (MyInCallService.channel != null) {
|
if (MyInCallService.channel != null) {
|
||||||
MyInCallService.channel?.invokeMethod("incomingCallFromNotification", mapOf(
|
MyInCallService.channel?.invokeMethod("incomingCallFromNotification", mapOf(
|
||||||
"phoneNumber" to phoneNumber
|
"phoneNumber" to phoneNumber,
|
||||||
|
"wasPhoneLocked" to wasPhoneLocked
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
// Store the intent data if Flutter isn't ready yet
|
|
||||||
pendingIncomingCall = Pair(phoneNumber, true)
|
pendingIncomingCall = Pair(phoneNumber, true)
|
||||||
Log.d(TAG, "Flutter channel not ready, storing pending call: $phoneNumber")
|
Log.d(TAG, "Flutter channel not ready, storing pending call: $phoneNumber")
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.icing.dialer.services
|
package com.icing.dialer.services
|
||||||
|
|
||||||
|
import android.app.KeyguardManager
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
@ -20,6 +21,7 @@ class MyInCallService : InCallService() {
|
|||||||
private const val TAG = "MyInCallService"
|
private const val TAG = "MyInCallService"
|
||||||
private const val NOTIFICATION_CHANNEL_ID = "incoming_call_channel"
|
private const val NOTIFICATION_CHANNEL_ID = "incoming_call_channel"
|
||||||
private const val NOTIFICATION_ID = 1
|
private const val NOTIFICATION_ID = 1
|
||||||
|
var wasPhoneLocked: Boolean = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private val callCallback = object : Call.Callback() {
|
private val callCallback = object : Call.Callback() {
|
||||||
@ -36,13 +38,20 @@ class MyInCallService : InCallService() {
|
|||||||
Log.d(TAG, "State changed: $stateStr for call ${call.details.handle}")
|
Log.d(TAG, "State changed: $stateStr for call ${call.details.handle}")
|
||||||
channel?.invokeMethod("callStateChanged", mapOf(
|
channel?.invokeMethod("callStateChanged", mapOf(
|
||||||
"callId" to call.details.handle.toString(),
|
"callId" to call.details.handle.toString(),
|
||||||
"state" to stateStr
|
"state" to stateStr,
|
||||||
|
"wasPhoneLocked" to wasPhoneLocked
|
||||||
))
|
))
|
||||||
if (state == Call.STATE_RINGING) {
|
if (state == Call.STATE_RINGING) {
|
||||||
|
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
|
||||||
|
wasPhoneLocked = keyguardManager.isKeyguardLocked
|
||||||
|
Log.d(TAG, "Phone locked at ringing: $wasPhoneLocked")
|
||||||
showIncomingCallScreen(call.details.handle.toString().replace("tel:", ""))
|
showIncomingCallScreen(call.details.handle.toString().replace("tel:", ""))
|
||||||
} else if (state == Call.STATE_DISCONNECTED || state == Call.STATE_DISCONNECTING) {
|
} else if (state == Call.STATE_DISCONNECTED || state == Call.STATE_DISCONNECTING) {
|
||||||
Log.d(TAG, "Call ended: ${call.details.handle}")
|
Log.d(TAG, "Call ended: ${call.details.handle}, wasPhoneLocked: $wasPhoneLocked")
|
||||||
channel?.invokeMethod("callEnded", mapOf("callId" to call.details.handle.toString()))
|
channel?.invokeMethod("callEnded", mapOf(
|
||||||
|
"callId" to call.details.handle.toString(),
|
||||||
|
"wasPhoneLocked" to wasPhoneLocked
|
||||||
|
))
|
||||||
currentCall = null
|
currentCall = null
|
||||||
cancelNotification()
|
cancelNotification()
|
||||||
}
|
}
|
||||||
@ -64,6 +73,9 @@ class MyInCallService : InCallService() {
|
|||||||
"state" to stateStr
|
"state" to stateStr
|
||||||
))
|
))
|
||||||
if (stateStr == "ringing") {
|
if (stateStr == "ringing") {
|
||||||
|
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
|
||||||
|
wasPhoneLocked = keyguardManager.isKeyguardLocked
|
||||||
|
Log.d(TAG, "Phone locked at call added: $wasPhoneLocked")
|
||||||
showIncomingCallScreen(call.details.handle.toString().replace("tel:", ""))
|
showIncomingCallScreen(call.details.handle.toString().replace("tel:", ""))
|
||||||
}
|
}
|
||||||
call.registerCallback(callCallback)
|
call.registerCallback(callCallback)
|
||||||
@ -71,9 +83,12 @@ class MyInCallService : InCallService() {
|
|||||||
|
|
||||||
override fun onCallRemoved(call: Call) {
|
override fun onCallRemoved(call: Call) {
|
||||||
super.onCallRemoved(call)
|
super.onCallRemoved(call)
|
||||||
Log.d(TAG, "Call removed: ${call.details.handle}")
|
Log.d(TAG, "Call removed: ${call.details.handle}, wasPhoneLocked: $wasPhoneLocked")
|
||||||
call.unregisterCallback(callCallback)
|
call.unregisterCallback(callCallback)
|
||||||
channel?.invokeMethod("callRemoved", mapOf("callId" to call.details.handle.toString()))
|
channel?.invokeMethod("callRemoved", mapOf(
|
||||||
|
"callId" to call.details.handle.toString(),
|
||||||
|
"wasPhoneLocked" to wasPhoneLocked
|
||||||
|
))
|
||||||
currentCall = null
|
currentCall = null
|
||||||
cancelNotification()
|
cancelNotification()
|
||||||
}
|
}
|
||||||
@ -90,41 +105,47 @@ class MyInCallService : InCallService() {
|
|||||||
putExtra("phoneNumber", phoneNumber)
|
putExtra("phoneNumber", phoneNumber)
|
||||||
putExtra("isIncomingCall", true)
|
putExtra("isIncomingCall", true)
|
||||||
putExtra("showIncomingCallScreen", true)
|
putExtra("showIncomingCallScreen", true)
|
||||||
|
putExtra("wasPhoneLocked", wasPhoneLocked)
|
||||||
}
|
}
|
||||||
startActivity(intent)
|
|
||||||
Log.d(TAG, "Launched MainActivity to show incoming call screen for $phoneNumber")
|
|
||||||
|
|
||||||
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (keyguardManager.isKeyguardLocked) {
|
||||||
val channel = NotificationChannel(
|
startActivity(intent)
|
||||||
NOTIFICATION_CHANNEL_ID,
|
Log.d(TAG, "Launched MainActivity directly for locked screen, phoneNumber: $phoneNumber")
|
||||||
"Incoming Calls",
|
} else {
|
||||||
NotificationManager.IMPORTANCE_HIGH
|
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
).apply {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
description = "Notifications for incoming calls"
|
val channel = NotificationChannel(
|
||||||
enableVibration(true)
|
NOTIFICATION_CHANNEL_ID,
|
||||||
setShowBadge(true)
|
"Incoming Calls",
|
||||||
|
NotificationManager.IMPORTANCE_HIGH
|
||||||
|
).apply {
|
||||||
|
description = "Notifications for incoming calls"
|
||||||
|
enableVibration(true)
|
||||||
|
setShowBadge(true)
|
||||||
|
}
|
||||||
|
notificationManager.createNotificationChannel(channel)
|
||||||
}
|
}
|
||||||
notificationManager.createNotificationChannel(channel)
|
|
||||||
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
|
this, 0, intent,
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT or (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
val notification = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
|
||||||
|
.setSmallIcon(android.R.drawable.ic_dialog_alert)
|
||||||
|
.setContentTitle("Incoming Call")
|
||||||
|
.setContentText("Call from $phoneNumber")
|
||||||
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||||
|
.setFullScreenIntent(pendingIntent, true)
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setOngoing(true)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
startActivity(intent)
|
||||||
|
notificationManager.notify(NOTIFICATION_ID, notification)
|
||||||
|
Log.d(TAG, "Launched MainActivity with notification for unlocked screen, phoneNumber: $phoneNumber")
|
||||||
}
|
}
|
||||||
|
|
||||||
val pendingIntent = PendingIntent.getActivity(
|
|
||||||
this, 0, intent,
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0)
|
|
||||||
)
|
|
||||||
|
|
||||||
val notification = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
|
|
||||||
.setSmallIcon(android.R.drawable.ic_dialog_alert)
|
|
||||||
.setContentTitle("Incoming Call")
|
|
||||||
.setContentText("Call from $phoneNumber")
|
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
|
||||||
.setContentIntent(pendingIntent)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setOngoing(true)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
notificationManager.notify(NOTIFICATION_ID, notification)
|
|
||||||
Log.d(TAG, "Notification shown for incoming call from $phoneNumber")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cancelNotification() {
|
private fun cancelNotification() {
|
||||||
|
@ -7,17 +7,14 @@ class CallService {
|
|||||||
static const MethodChannel _channel = MethodChannel('call_service');
|
static const MethodChannel _channel = MethodChannel('call_service');
|
||||||
static String? currentPhoneNumber;
|
static String? currentPhoneNumber;
|
||||||
static bool _isCallPageVisible = false;
|
static bool _isCallPageVisible = false;
|
||||||
|
static Map<String, dynamic>? _pendingCall;
|
||||||
|
static bool wasPhoneLocked = false;
|
||||||
|
|
||||||
static final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
static final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
|
||||||
CallService() {
|
CallService() {
|
||||||
_channel.setMethodCallHandler((call) async {
|
_channel.setMethodCallHandler((call) async {
|
||||||
final context = navigatorKey.currentContext;
|
print('CallService: Handling method call: ${call.method}');
|
||||||
if (context == null) {
|
|
||||||
print('CallService: Navigator context is null, cannot navigate');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (call.method) {
|
switch (call.method) {
|
||||||
case "callAdded":
|
case "callAdded":
|
||||||
final phoneNumber = call.arguments["callId"] as String;
|
final phoneNumber = call.arguments["callId"] as String;
|
||||||
@ -25,43 +22,84 @@ class CallService {
|
|||||||
currentPhoneNumber = phoneNumber.replaceFirst('tel:', '');
|
currentPhoneNumber = phoneNumber.replaceFirst('tel:', '');
|
||||||
print('CallService: Call added, number: $currentPhoneNumber, state: $state');
|
print('CallService: Call added, number: $currentPhoneNumber, state: $state');
|
||||||
if (state == "ringing") {
|
if (state == "ringing") {
|
||||||
_navigateToIncomingCallPage(context);
|
_handleIncomingCall(phoneNumber);
|
||||||
} else {
|
} else {
|
||||||
_navigateToCallPage(context);
|
_navigateToCallPage();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "callStateChanged":
|
case "callStateChanged":
|
||||||
final state = call.arguments["state"] as String;
|
final state = call.arguments["state"] as String;
|
||||||
print('CallService: State changed to $state');
|
wasPhoneLocked = call.arguments["wasPhoneLocked"] as bool? ?? false;
|
||||||
|
print('CallService: State changed to $state, wasPhoneLocked: $wasPhoneLocked');
|
||||||
if (state == "disconnected" || state == "disconnecting") {
|
if (state == "disconnected" || state == "disconnecting") {
|
||||||
_closeCallPage(context);
|
_closeCallPage();
|
||||||
|
if (wasPhoneLocked) {
|
||||||
|
_channel.invokeMethod("callEndedFromFlutter");
|
||||||
|
}
|
||||||
} else if (state == "active" || state == "dialing") {
|
} else if (state == "active" || state == "dialing") {
|
||||||
_navigateToCallPage(context);
|
_navigateToCallPage();
|
||||||
} else if (state == "ringing") {
|
} else if (state == "ringing") {
|
||||||
_navigateToIncomingCallPage(context);
|
final phoneNumber = call.arguments["callId"] as String;
|
||||||
|
_handleIncomingCall(phoneNumber.replaceFirst('tel:', ''));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "callEnded":
|
case "callEnded":
|
||||||
case "callRemoved":
|
case "callRemoved":
|
||||||
print('CallService: Call ended/removed');
|
wasPhoneLocked = call.arguments["wasPhoneLocked"] as bool? ?? false;
|
||||||
_closeCallPage(context);
|
print('CallService: Call ended/removed, wasPhoneLocked: $wasPhoneLocked');
|
||||||
|
_closeCallPage();
|
||||||
|
if (wasPhoneLocked) {
|
||||||
|
_channel.invokeMethod("callEndedFromFlutter");
|
||||||
|
}
|
||||||
currentPhoneNumber = null;
|
currentPhoneNumber = null;
|
||||||
break;
|
break;
|
||||||
case "incomingCallFromNotification":
|
case "incomingCallFromNotification":
|
||||||
final phoneNumber = call.arguments["phoneNumber"] as String;
|
final phoneNumber = call.arguments["phoneNumber"] as String;
|
||||||
|
wasPhoneLocked = call.arguments["wasPhoneLocked"] as bool? ?? false;
|
||||||
currentPhoneNumber = phoneNumber;
|
currentPhoneNumber = phoneNumber;
|
||||||
print('CallService: Incoming call from notification: $phoneNumber');
|
print('CallService: Incoming call from notification: $phoneNumber, wasPhoneLocked: $wasPhoneLocked');
|
||||||
_navigateToIncomingCallPage(context);
|
_handleIncomingCall(phoneNumber);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Signal Flutter is ready
|
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
|
||||||
_channel.invokeMethod("flutterReady");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _navigateToCallPage(BuildContext context) {
|
void _handleIncomingCall(String phoneNumber) {
|
||||||
|
final context = navigatorKey.currentContext;
|
||||||
|
if (context == null) {
|
||||||
|
print('CallService: Context is null, queuing incoming call: $phoneNumber');
|
||||||
|
_pendingCall = {"phoneNumber": phoneNumber};
|
||||||
|
Future.delayed(Duration(milliseconds: 500), () => _checkPendingCall());
|
||||||
|
} else {
|
||||||
|
_navigateToIncomingCallPage(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _checkPendingCall() {
|
||||||
|
if (_pendingCall != null) {
|
||||||
|
final context = navigatorKey.currentContext;
|
||||||
|
if (context != null) {
|
||||||
|
print('CallService: Processing queued call: ${_pendingCall!["phoneNumber"]}');
|
||||||
|
currentPhoneNumber = _pendingCall!["phoneNumber"];
|
||||||
|
_navigateToIncomingCallPage(context);
|
||||||
|
_pendingCall = null;
|
||||||
|
} else {
|
||||||
|
print('CallService: Context still null, retrying...');
|
||||||
|
Future.delayed(Duration(milliseconds: 500), () => _checkPendingCall());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _navigateToCallPage() {
|
||||||
|
final context = navigatorKey.currentContext;
|
||||||
|
if (context == null) {
|
||||||
|
print('CallService: Cannot navigate to CallPage, context is null');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_isCallPageVisible) {
|
||||||
|
print('CallService: CallPage already visible, skipping navigation');
|
||||||
|
return;
|
||||||
|
}
|
||||||
print('CallService: Navigating to CallPage');
|
print('CallService: Navigating to CallPage');
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
@ -81,6 +119,10 @@ class CallService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _navigateToIncomingCallPage(BuildContext context) {
|
void _navigateToIncomingCallPage(BuildContext context) {
|
||||||
|
if (_isCallPageVisible) {
|
||||||
|
print('CallService: IncomingCallPage already visible, skipping navigation');
|
||||||
|
return;
|
||||||
|
}
|
||||||
print('CallService: Navigating to IncomingCallPage');
|
print('CallService: Navigating to IncomingCallPage');
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
@ -99,8 +141,13 @@ class CallService {
|
|||||||
_isCallPageVisible = true;
|
_isCallPageVisible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _closeCallPage(BuildContext context) {
|
void _closeCallPage() {
|
||||||
print('CallService: Attempting to close call page, _isCallPageVisible: $_isCallPageVisible');
|
final context = navigatorKey.currentContext;
|
||||||
|
if (context == null) {
|
||||||
|
print('CallService: Cannot close page, context is null');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
print('CallService: Closing call page, _isCallPageVisible: $_isCallPageVisible');
|
||||||
if (Navigator.canPop(context)) {
|
if (Navigator.canPop(context)) {
|
||||||
print('CallService: Popping call page');
|
print('CallService: Popping call page');
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
@ -133,7 +180,7 @@ class CallService {
|
|||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text("Error making call: $e")),
|
SnackBar(content: Text("Error making call: $e")),
|
||||||
);
|
);
|
||||||
rethrow;
|
return {"status": "error", "message": e.toString()};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +201,7 @@ class CallService {
|
|||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text("Error hanging up call: $e")),
|
SnackBar(content: Text("Error hanging up call: $e")),
|
||||||
);
|
);
|
||||||
rethrow;
|
return {"status": "error", "message": e.toString()};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user