parent
90cea674d4
commit
1867c025fd
@ -1,4 +1,3 @@
|
|||||||
// File: android/app/src/main/kotlin/com/example/dialer/MainActivity.kt
|
|
||||||
package com.example.dialer
|
package com.example.dialer
|
||||||
|
|
||||||
import android.app.role.RoleManager
|
import android.app.role.RoleManager
|
||||||
@ -7,6 +6,7 @@ import android.content.ComponentName
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
|
import android.content.pm.PackageManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
@ -14,6 +14,8 @@ import android.telecom.PhoneAccount
|
|||||||
import android.telecom.PhoneAccountHandle
|
import android.telecom.PhoneAccountHandle
|
||||||
import android.telecom.TelecomManager
|
import android.telecom.TelecomManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
@ -25,6 +27,9 @@ class MainActivity : FlutterActivity() {
|
|||||||
// Request code for the default-dialer request.
|
// Request code for the default-dialer request.
|
||||||
private val DEFAULT_DIALER_REQUEST_CODE = 1001
|
private val DEFAULT_DIALER_REQUEST_CODE = 1001
|
||||||
|
|
||||||
|
// Request code for runtime permissions.
|
||||||
|
private val PERMISSION_REQUEST_CODE = 1002
|
||||||
|
|
||||||
// BroadcastReceiver to catch incoming call events from our ConnectionService.
|
// BroadcastReceiver to catch incoming call events from our ConnectionService.
|
||||||
private val incomingCallReceiver = object : BroadcastReceiver() {
|
private val incomingCallReceiver = object : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
@ -49,6 +54,9 @@ class MainActivity : FlutterActivity() {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
// Request runtime permissions.
|
||||||
|
checkAndRequestPermissions()
|
||||||
|
|
||||||
// Create the intent filter for incoming calls.
|
// Create the intent filter for incoming calls.
|
||||||
val filter = IntentFilter("com.example.dialer.INCOMING_CALL")
|
val filter = IntentFilter("com.example.dialer.INCOMING_CALL")
|
||||||
// Register the receiver. (For Android 13+ we must specify not exported.)
|
// Register the receiver. (For Android 13+ we must specify not exported.)
|
||||||
@ -121,16 +129,30 @@ class MainActivity : FlutterActivity() {
|
|||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
if (requestCode == DEFAULT_DIALER_REQUEST_CODE) {
|
if (requestCode == DEFAULT_DIALER_REQUEST_CODE) {
|
||||||
Log.d("MainActivity", "onActivityResult received: resultCode=$resultCode")
|
Log.d("MainActivity", "onActivityResult received: resultCode=$resultCode")
|
||||||
// Delay a short time before checking the role.
|
when (resultCode) {
|
||||||
Handler(mainLooper).postDelayed({
|
RESULT_OK -> {
|
||||||
if (isDefaultDialer()) {
|
Log.d("MainActivity", "User granted default dialer role")
|
||||||
Log.d("MainActivity", "Default dialer successfully set")
|
Handler(mainLooper).postDelayed({
|
||||||
registerManagedPhoneAccount()
|
if (isDefaultDialer()) {
|
||||||
notifyDefaultDialerSet()
|
Log.d("MainActivity", "Default dialer successfully set")
|
||||||
} else {
|
registerManagedPhoneAccount()
|
||||||
Log.d("MainActivity", "Default dialer not set")
|
notifyDefaultDialerSet()
|
||||||
|
} else {
|
||||||
|
Log.d("MainActivity", "Default dialer not set")
|
||||||
|
// Notify Flutter that the default dialer role was not set
|
||||||
|
methodChannel.invokeMethod("onDefaultDialerNotSet", null)
|
||||||
|
}
|
||||||
|
}, 500)
|
||||||
}
|
}
|
||||||
}, 500)
|
RESULT_CANCELED -> {
|
||||||
|
Log.d("MainActivity", "User denied default dialer role")
|
||||||
|
// Notify Flutter that the user denied the request
|
||||||
|
methodChannel.invokeMethod("onDefaultDialerDenied", null)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
Log.d("MainActivity", "Unknown resultCode: $resultCode")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,6 +168,7 @@ class MainActivity : FlutterActivity() {
|
|||||||
.setShortDescription("Icing Custom Dialer")
|
.setShortDescription("Icing Custom Dialer")
|
||||||
.build()
|
.build()
|
||||||
telecomManager.registerPhoneAccount(phoneAccount)
|
telecomManager.registerPhoneAccount(phoneAccount)
|
||||||
|
Log.d("MainActivity", "PhoneAccount registered")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify Flutter that we are now the default dialer.
|
// Notify Flutter that we are now the default dialer.
|
||||||
@ -157,4 +180,39 @@ class MainActivity : FlutterActivity() {
|
|||||||
private fun notifyIncomingCall(phoneNumber: String) {
|
private fun notifyIncomingCall(phoneNumber: String) {
|
||||||
methodChannel.invokeMethod("onIncomingCall", phoneNumber)
|
methodChannel.invokeMethod("onIncomingCall", phoneNumber)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Check and request runtime permissions.
|
||||||
|
private fun checkAndRequestPermissions() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
val permissionsNeeded = mutableListOf<String>()
|
||||||
|
val permissionsToRequest = mutableListOf<String>()
|
||||||
|
|
||||||
|
// Check if permissions are granted
|
||||||
|
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
permissionsToRequest.add(android.Manifest.permission.READ_PHONE_STATE)
|
||||||
|
}
|
||||||
|
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
permissionsToRequest.add(android.Manifest.permission.CALL_PHONE)
|
||||||
|
}
|
||||||
|
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ANSWER_PHONE_CALLS) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
permissionsToRequest.add(android.Manifest.permission.ANSWER_PHONE_CALLS)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request permissions if needed
|
||||||
|
if (permissionsToRequest.isNotEmpty()) {
|
||||||
|
ActivityCompat.requestPermissions(this, permissionsToRequest.toTypedArray(), PERMISSION_REQUEST_CODE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||||
|
if (requestCode == PERMISSION_REQUEST_CODE) {
|
||||||
|
if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
|
||||||
|
Log.d("MainActivity", "All permissions granted")
|
||||||
|
} else {
|
||||||
|
Log.d("MainActivity", "Some permissions denied")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
// File: lib/main.dart
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
@ -25,6 +24,8 @@ class _IcingDialerAppState extends State<IcingDialerApp> {
|
|||||||
platform.setMethodCallHandler(handleMethodCalls);
|
platform.setMethodCallHandler(handleMethodCalls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Future<void> handleMethodCalls(MethodCall call) async {
|
Future<void> handleMethodCalls(MethodCall call) async {
|
||||||
switch (call.method) {
|
switch (call.method) {
|
||||||
case 'onDefaultDialerSet':
|
case 'onDefaultDialerSet':
|
||||||
@ -33,6 +34,10 @@ class _IcingDialerAppState extends State<IcingDialerApp> {
|
|||||||
isDefaultDialer = true;
|
isDefaultDialer = true;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case 'onDefaultDialerDenied':
|
||||||
|
// Show a message to the user when they deny the request.
|
||||||
|
_showDefaultDialerDeniedDialog();
|
||||||
|
break;
|
||||||
case 'onIncomingCall':
|
case 'onIncomingCall':
|
||||||
final phoneNumber = call.arguments as String? ?? "Unknown";
|
final phoneNumber = call.arguments as String? ?? "Unknown";
|
||||||
_showIncomingCallDialog(phoneNumber);
|
_showIncomingCallDialog(phoneNumber);
|
||||||
@ -42,6 +47,26 @@ class _IcingDialerAppState extends State<IcingDialerApp> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show a dialog when the user denies the default dialer request.
|
||||||
|
void _showDefaultDialerDeniedDialog() {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
title: const Text('Permission Denied'),
|
||||||
|
content: const Text(
|
||||||
|
'To use this app as your default dialer, please grant the permission when prompted.'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: const Text('OK'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Show a dialog when an incoming call is intercepted.
|
// Show a dialog when an incoming call is intercepted.
|
||||||
void _showIncomingCallDialog(String phoneNumber) {
|
void _showIncomingCallDialog(String phoneNumber) {
|
||||||
showDialog(
|
showDialog(
|
||||||
@ -76,6 +101,10 @@ class _IcingDialerAppState extends State<IcingDialerApp> {
|
|||||||
await platform.invokeMethod('requestDefaultDialer');
|
await platform.invokeMethod('requestDefaultDialer');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error requesting default dialer: $e');
|
print('Error requesting default dialer: $e');
|
||||||
|
// Show an error message if the request fails.
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text('Error requesting default dialer: $e')),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,4 +164,4 @@ class CallScreen extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user