feat: open dialer on top of locked screen when incoming call
All checks were successful
/ mirror (push) Successful in 5s
/ build (push) Successful in 9m57s
/ build-stealth (push) Successful in 9m55s

This commit is contained in:
Florian Griffon 2025-04-08 16:10:54 +03:00
parent 20228f6389
commit d1a294d772
4 changed files with 37 additions and 14 deletions

View File

@ -28,7 +28,9 @@
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
android:windowSoftInputMode="adjustResize"
android:showWhenLocked="true"
android:turnScreenOn="true">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues

View File

@ -9,6 +9,8 @@ import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.provider.CallLog
import android.telecom.TelecomManager
import android.util.Log
@ -27,6 +29,7 @@ class MainActivity : FlutterActivity() {
private val TAG = "MainActivity"
private val REQUEST_CODE_SET_DEFAULT_DIALER = 1001
private val REQUEST_CODE_CALL_LOG_PERMISSION = 1002
private var pendingIncomingCall: Pair<String?, Boolean>? = null // Store incoming call data
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -57,12 +60,10 @@ class MainActivity : FlutterActivity() {
"makeGsmCall" -> {
val phoneNumber = call.argument<String>("phoneNumber")
if (phoneNumber != null) {
try {
val intent = Intent(Intent.ACTION_CALL, Uri.parse("tel:$phoneNumber"))
startActivity(intent)
val success = CallService.makeGsmCall(this, phoneNumber) // Use CallService
if (success) {
result.success(mapOf("status" to "calling", "phoneNumber" to phoneNumber))
} catch (e: Exception) {
Log.e(TAG, "Failed to make GSM call: ${e.message}")
} else {
result.error("CALL_FAILED", "Failed to initiate call", null)
}
} else {
@ -98,6 +99,18 @@ class MainActivity : FlutterActivity() {
result.error("ANSWER_FAILED", "No active call to answer", null)
}
}
"flutterReady" -> { // New method to signal Flutter is initialized
Log.d(TAG, "Flutter is ready")
pendingIncomingCall?.let { (phoneNumber, showScreen) ->
if (showScreen) {
MyInCallService.channel?.invokeMethod("incomingCallFromNotification", mapOf(
"phoneNumber" to phoneNumber
))
pendingIncomingCall = null // Clear after handling
}
}
result.success(true)
}
else -> result.notImplemented()
}
}
@ -217,9 +230,15 @@ class MainActivity : FlutterActivity() {
val showScreen = it.getBooleanExtra("showIncomingCallScreen", false)
Log.d(TAG, "Received incoming call intent for $phoneNumber, showScreen=$showScreen")
if (showScreen) {
MyInCallService.channel?.invokeMethod("incomingCallFromNotification", mapOf(
"phoneNumber" to phoneNumber
))
if (MyInCallService.channel != null) {
MyInCallService.channel?.invokeMethod("incomingCallFromNotification", mapOf(
"phoneNumber" to phoneNumber
))
} else {
// Store the intent data if Flutter isn't ready yet
pendingIncomingCall = Pair(phoneNumber, true)
Log.d(TAG, "Flutter channel not ready, storing pending call: $phoneNumber")
}
}
}
}

View File

@ -85,17 +85,15 @@ class MyInCallService : InCallService() {
}
private fun showIncomingCallScreen(phoneNumber: String) {
// Launch MainActivity with intent to show IncomingCallPage
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
putExtra("phoneNumber", phoneNumber)
putExtra("isIncomingCall", true)
putExtra("showIncomingCallScreen", true) // New flag to signal immediate UI
putExtra("showIncomingCallScreen", true)
}
startActivity(intent)
Log.d(TAG, "Launched MainActivity to show incoming call screen for $phoneNumber")
// Optional: Keep notification as a fallback
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
@ -116,7 +114,7 @@ class MyInCallService : InCallService() {
)
val notification = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(android.R.drawable.ic_dialog_alert) // Replace with your app icon
.setSmallIcon(android.R.drawable.ic_dialog_alert)
.setContentTitle("Incoming Call")
.setContentText("Call from $phoneNumber")
.setPriority(NotificationCompat.PRIORITY_HIGH)

View File

@ -55,6 +55,10 @@ class CallService {
break;
}
});
// Signal Flutter is ready
WidgetsFlutterBinding.ensureInitialized();
_channel.invokeMethod("flutterReady");
}
void _navigateToCallPage(BuildContext context) {