flutter-webrtc / callkeep

iOS CallKit and Android ConnectionService for Flutter
MIT License
137 stars 151 forks source link

Unhandled Exception: PlatformException on android.permission.READ_PHONE_NUMBERS #174

Open andw99 opened 1 year ago

andw99 commented 1 year ago

I have an issue that I cannot get around...

Note that using an Android 10 phone, everything works and VoiP and Video calls can be made...

But when attempting to use an Android 12 phone it always fails with the following exception.

E/flutter (16778): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(error, Neither user 10550 nor current process has android.permission.READ_PHONE_NUMBERS., null, java.lang.SecurityException: Neither user 10550 nor current process has android.permission.READ_PHONE_NUMBERS.
E/flutter (16778):  at android.os.Parcel.createExceptionOrNull(Parcel.java:3040)
E/flutter (16778):  at android.os.Parcel.createException(Parcel.java:3024)
E/flutter (16778):  at android.os.Parcel.readException(Parcel.java:3007)
E/flutter (16778):  at android.os.Parcel.readException(Parcel.java:2949)
E/flutter (16778):  at com.android.internal.telecom.ITelecomService$Stub$Proxy.getPhoneAccount(ITelecomService.java:1672)
E/flutter (16778):  at android.telecom.TelecomManager.getPhoneAccount(TelecomManager.java:1436)
E/flutter (16778):  at io.wazo.callkeep.CallKeepModule.hasPhoneAccount(CallKeepModule.java:663)
E/flutter (16778):  at io.wazo.callkeep.CallKeepModule.hasPhoneAccount(CallKeepModule.java:498)
E/flutter (16778):  at io.wazo.callkeep.CallKeepModule.handleMethodCall(CallKeepModule.java:177)
E/flutter (16778):  at com.github.cloudwebrtc.flutter_callkeep.FlutterCallkeepPlugin.onMethodCall(FlutterCallkeepPlugin.java:69)
E/flutter (16778):  at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:258)
E/flutter (16778):  at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:295)
E/flutter (16778):  at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(DartMessenger.java:322)
E/flutter (16778):  at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12)
E/flutter (16778):  at android.os.Handler.handleCallback(Handler.java:942)
E/flutter (16778):  at android.os.Handler.dispatchMessage(Handler.java:99)
E/flutter (16778):  at android.os.Looper.loopOnce(Looper.java:240)
E/flutter (16778):  at android.os.Looper.loop(Looper.java:351)
E/flutter (16778):  at android.app.ActivityThread.main(ActivityThread.java:8381)
E/flutter (16778):  at java.lang.reflect.Method.invoke(Native Method)
E/flutter (16778):  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584)
E/flutter (16778):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1013)
E/flutter (16778): )

I am calling setup with the following code... note that I have created an additional method invoke within MainActivity.kt to attempt to force the permission request - this does not come back with an error but it also does not put up a request dialog.

final callSetup = <String, dynamic>{
    'ios': {
      'appName': AppConfig.applicationName,
    },
    'android': {
      'alertTitle': 'Permissions required',
      'alertDescription': 'Conciel needs to access your phone accounts',
      'cancelButton': 'Cancel',
      'okButton': 'ok',
      // Required to get audio in background when using Android 11
      'foregroundService': {
        'channelId': 'chat.talk.conciel.call',
        'channelName': 'Conciel Call',
        'notificationTitle': 'Conciel is running in the background',
        'notificationIcon': 'mipmap/ic_notification_launcher',
      },
      'additionalPermissions': [''],
    },
  };

  void requestReadPhoneNumbersPermission() async {
    try {
      await concielPlatform.invokeMethod('requestReadPhoneNumbersPermission');
    } on PlatformException catch (e) {
      Logs().e('Failed to request READ_PHONE_NUMBERS permission: ${e.message}');
    }
  }

await Permission.phone.request().isGranted;
requestReadPhoneNumbersPermission();
await _callKeep.setup(
      context,
      callSetup,
);

in the MainActivity.kt - I have included the following code to invoke permission request on READ_PHONE_NUMBERS...

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        if (requestCode == REQUEST_READ_PHONE_NUMBERS) {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // The READ_PHONE_NUMBERS permission was granted
                Log.d("MainActivity", "READ_PHONE_NUMBERS permission granted")
            } else {
                // The READ_PHONE_NUMBERS permission was not granted
                Log.d("MainActivity", "READ_PHONE_NUMBERS permission not granted")
            }
        }
    }

As it stands, I am unable to use CallKeep to handle calls on a phone above Android 10.

andw99 commented 1 year ago

I just noted the Kotlin code was the permission check... this is the invoke permission code...

        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if (call.method == "requestReadPhoneNumbersPermission") {
                // Check if the READ_PHONE_NUMBERS permission is already granted
                if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_NUMBERS) != PackageManager.PERMISSION_GRANTED) {
                    // Request the READ_PHONE_NUMBERS permission
                    ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_NUMBERS), REQUEST_READ_PHONE_NUMBERS)
                }
                result.success(null)
            } else {
                result.notImplemented()
            }
        }
    }
rashedswen commented 1 year ago

you can just add this to your android manifest file

<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />

andw99 commented 1 year ago

you can just add this to your android manifest file

<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />

@rashedswen - It is already in the android manifest, all other permissions requested in Android manifest work as expected, this one does not.

rashedswen commented 1 year ago

Do you try to setup the callkeep in main or first page of your app I do that and that work will and request permission when the app opens

andw99 commented 1 year ago

Yes, the setup and permission checks all occur once the app opens. From my understanding CallKeep should allow use of system managed Android ConnectionService - but from my recent research, on some makes and models this is not possible as their Android Settings do not permit access to this, hence the exception.