MrHertal / react-native-twilio-phone

Twilio Voice React Native module.
MIT License
154 stars 66 forks source link

Handle Incoming Call When app is in background state #10

Closed skibrit closed 3 years ago

skibrit commented 3 years ago

Hi,

First of all thanks a lot for the library which is very helpful. By following the documentation, I've managed to integrate Twilio voice call functionality in a react native app. Outgoing call working fine, also receiving incoming calls as well.

But when the app is in the background state or killed then if the device receives an incoming call it just opens the app's homepage without showing callkeep UI. I'm not sure if that is the expected behavior that you've implemented. If so is there any event that exists where we can listen and get the data ex. caller phoneNumber and trigger the callkeep from the app.

I've tried these events CallInvite , CallRinging but these events don't; trigger when the app comes in the foreground state.

Note: I'm only working on the android platform at the moment

MrHertal commented 3 years ago

Hi, thanks for the support!

Indeed this is not the expected behavior, CallKeep UI should show up (even if app is awaken behind the hood).

What version of Android are you using? on which device? Also what dependencies versions did you install?

I have updated all dependencies yesterday, and the example app works well on Android.

Here are the last dependencies versions of the example app:

  "dependencies": {
    "@react-native-firebase/app": "^10.0.0",
    "@react-native-firebase/messaging": "^10.0.0",
    "react": "16.13.1",
    "react-native": "0.63.3",
    "react-native-callkeep": "^4.0.1",
    "react-native-voip-push-notification": "^3.0.0"
  },

Migrating to CallKeep v4 (adds Android 11 support) also requires:

MrHertal commented 3 years ago

I thought about the fact that your app is awake but the CallKeep UI does not show.

Maybe it is simply a permission problem, did you allow your app to access phone app?

skibrit commented 3 years ago

Hi, I've tested on android 7,10 emulators and real devices. In both cases, CallKeep UI doesn't show up when the app wake up from killed to foreground state

Here is the sdk version I'm using

buildToolsVersion = "28.0.3"
minSdkVersion = 24
compileSdkVersion = 30
targetSdkVersion = 30
kotlinVersion = "1.3.72"

and all the required packages are up to date to the latest version. I've used the same param mentioned in your documentation to initiate the callkeep instance.

I think I've added all the required permission as well

<uses-permission
            android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
            tools:ignore="ProtectedPermissions" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-feature android:name="android.hardware.microphone" android:required="true" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.VIBRATE" />

But Call Ui doesn't show when the app comes into foreground. Though it works fine when the app is in the foreground.

skibrit commented 3 years ago

In Android 10 app doesn't actually get open when the app is killed. it only just receives a notification that only shows the app name and nothing else.

mobile

MrHertal commented 3 years ago

I tested incoming calls with the example app.

Android 9 (Real device - Samsung G9)

Android 10 (Emulator - Nexus 5X)

Android 11 (Emulator - Pixel 4)

In all cases, I could not reproduce your notification problem (receiving a notification without buttons to accept or decline). I only have one real device (Samsung G9) and everything works with it. So I cannot tell if the killed state problem comes from emulating device or not.

Let's compare the logs. Here are the logs of that case:

Android 10 (Emulator - Nexus 5X)

log1 log2

call

Can you compare with your logs to see if something shows up?

cunneen commented 3 years ago

Thanks for sharing this project @MrHertal . On android 10 I also get this: • app killed: KO - nothing happens on the screen

FCM does receive the notification and it does pass it through to TwilioPhone, but there's no UI at all on the lock screen. But in this case I don't get any UI notification at all; is your screenshot above from this ('app killed') case or is it the 'app in background' case?

When I first kill the app, it looks like some permissions are revoked (SYSTEM_ALERT_WINDOW and BIND_TELECOM_CONNECTION_SERVICE), followed a few seconds later by an error cannot create TelephonyManager from ComponentInfo. Could this be the cause of the issue?

<aside> With a completely different example I've seen an empty UI notification that @skibrit describes, and I suspect it's something to do with the payload. I haven't seen the behaviour in this example.

=====
Killed the app:
=====

2020-12-10 11:08:25.524 2042-2065/? I/ActivityManager: Killing 11032:net.appworkshop.reactnativetwiliophone/u0a139 (adj 905): remove task
2020-12-10 11:08:25.624 2042-2142/? W/InputDispatcher: channel 'caab3ec net.appworkshop.reactnativetwiliophone/net.appworkshop.reactnativetwiliophone.MainActivity (server)' ~ Consumer closed input channel or an error occurred.  events=0x9
2020-12-10 11:08:25.624 2042-2142/? E/InputDispatcher: channel 'caab3ec net.appworkshop.reactnativetwiliophone/net.appworkshop.reactnativetwiliophone.MainActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
2020-12-10 11:08:25.629 2042-2060/? I/WindowManager: WIN DEATH: Window{caab3ec u0 net.appworkshop.reactnativetwiliophone/net.appworkshop.reactnativetwiliophone.MainActivity}
2020-12-10 11:08:25.629 2042-2060/? W/InputDispatcher: Attempted to unregister already unregistered input channel 'caab3ec net.appworkshop.reactnativetwiliophone/net.appworkshop.reactnativetwiliophone.MainActivity (server)'
====> 2020-12-10 11:08:51.634 2042-2083/? I/PackageManager: Un-granting permission android.permission.SYSTEM_ALERT_WINDOW from package net.appworkshop.reactnativetwiliophone (protectionLevel=1250 flags=0x38883e46)
====> 2020-12-10 11:08:51.634 2042-2083/? I/PackageManager: Un-granting permission android.permission.BIND_TELECOM_CONNECTION_SERVICE from package net.appworkshop.reactnativetwiliophone (protectionLevel=18 flags=0x38883e46)
====> 2020-12-10 11:08:56.507 2353-2353/? E/VvmPkgInstalledRcvr: cannot create TelephonyManager from ComponentInfo{net.appworkshop.reactnativetwiliophone/io.wazo.callkeep.VoiceConnectionService}, ***, UserHandle{0}

2020-12-10 11:09:16.917 2042-2083/? I/PackageManager: Un-granting permission android.permission.SYSTEM_ALERT_WINDOW from package net.appworkshop.reactnativetwiliophone (protectionLevel=1250 flags=0x38883e46)
2020-12-10 11:09:16.917 2042-2083/? I/PackageManager: Un-granting permission android.permission.BIND_TELECOM_CONNECTION_SERVICE from package net.appworkshop.reactnativetwiliophone (protectionLevel=18 flags=0x38883e46)
2020-12-10 11:09:19.454 2353-2353/? E/VvmPkgInstalledRcvr: cannot create TelephonyManager from ComponentInfo{net.appworkshop.reactnativetwiliophone/io.wazo.callkeep.VoiceConnectionService}, ***, UserHandle{0}

=====
Receiving a call (from killed state):
=====

2020-12-10 11:10:29.685 2042-2072/? I/ActivityManager: Start proc 16811:net.appworkshop.reactnativetwiliophone/u0a139 for broadcast {net.appworkshop.reactnativetwiliophone/io.invertase.firebase.messaging.ReactNativeFirebaseMessagingReceiver}
2020-12-10 11:10:29.692 16811-16811/? I/tivetwiliophon: Not late-enabling -Xcheck:jni (already on)
2020-12-10 11:10:29.790 16811-16811/? E/tivetwiliophon: Unknown bits set in runtime_flags: 0x8000
2020-12-10 11:10:29.791 16811-16811/? W/tivetwiliophon: Unexpected CPU variant for X86 using defaults: x86
2020-12-10 11:10:33.978 16811-16858/? W/tivetwiliophon: JNI critical lock held for 33.831ms on Thread[17,tid=16858,Runnable,Thread*=0xd1846a00,peer=0x12c79f98,"pool-4-thread-1"]
2020-12-10 11:10:34.032 16811-16811/? D/SoLoader: adding application source: com.facebook.soloader.DirectorySoSource[root = /data/app/net.appworkshop.reactnativetwiliophone-s3ceXwUvc8MsF1TciRIWKA==/lib/x86 flags = 0]
2020-12-10 11:10:34.034 16811-16811/? D/SoLoader: adding backup source from : com.facebook.soloader.ApkSoSource[root = /data/data/net.appworkshop.reactnativetwiliophone/lib-main flags = 1]
2020-12-10 11:10:34.035 16811-16811/? D/SoLoader: Preparing SO source: com.facebook.soloader.DirectorySoSource[root = /data/app/net.appworkshop.reactnativetwiliophone-s3ceXwUvc8MsF1TciRIWKA==/lib/x86 flags = 0]
2020-12-10 11:10:34.035 16811-16811/? D/SoLoader: Preparing SO source: com.facebook.soloader.ApkSoSource[root = /data/data/net.appworkshop.reactnativetwiliophone/lib-main flags = 1]
2020-12-10 11:10:34.578 16811-16811/? I/fb-UnpackingSoSource: dso store is up-to-date: /data/user/0/net.appworkshop.reactnativetwiliophone/lib-main
2020-12-10 11:10:34.590 16811-16811/? D/SoLoader: libjscexecutor.so not found on /data/data/net.appworkshop.reactnativetwiliophone/lib-main
2020-12-10 11:10:34.590 16811-16811/? D/SoLoader: libjscexecutor.so found on /data/app/net.appworkshop.reactnativetwiliophone-s3ceXwUvc8MsF1TciRIWKA==/lib/x86
2020-12-10 11:10:35.594 16811-16811/? W/tivetwiliophon: Accessing hidden method Ldalvik/system/CloseGuard;->get()Ldalvik/system/CloseGuard; (greylist,core-platform-api, reflection, allowed)
2020-12-10 11:10:35.594 16811-16811/? W/tivetwiliophon: Accessing hidden method Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V (greylist,core-platform-api, reflection, allowed)
2020-12-10 11:10:35.594 16811-16811/? W/tivetwiliophon: Accessing hidden method Ldalvik/system/CloseGuard;->warnIfOpen()V (greylist,core-platform-api, reflection, allowed)
2020-12-10 11:10:35.840 16811-16874/? D/SoLoader: libfbjni.so not found on /data/data/net.appworkshop.reactnativetwiliophone/lib-main
2020-12-10 11:10:35.840 16811-16874/? D/SoLoader: libfbjni.so found on /data/app/net.appworkshop.reactnativetwiliophone-s3ceXwUvc8MsF1TciRIWKA==/lib/x86
2020-12-10 11:10:35.841 16811-16874/? D/SoLoader: libflipper.so not found on /data/data/net.appworkshop.reactnativetwiliophone/lib-main
2020-12-10 11:10:35.841 16811-16874/? D/SoLoader: libflipper.so found on /data/app/net.appworkshop.reactnativetwiliophone-s3ceXwUvc8MsF1TciRIWKA==/lib/x86
2020-12-10 11:10:36.793 16811-16811/? W/tivetwiliophon: Accessing hidden field Landroid/view/View;->mKeyedTags:Landroid/util/SparseArray; (greylist, reflection, allowed)
2020-12-10 11:10:36.793 16811-16811/? W/tivetwiliophon: Accessing hidden field Landroid/view/View;->mListenerInfo:Landroid/view/View$ListenerInfo; (greylist, reflection, allowed)
2020-12-10 11:10:36.793 16811-16811/? W/tivetwiliophon: Accessing hidden field Landroid/view/View$ListenerInfo;->mOnClickListener:Landroid/view/View$OnClickListener; (greylist, reflection, allowed)
2020-12-10 11:10:36.981 16811-16811/? D/SoLoader: libreactnativejni.so not found on /data/data/net.appworkshop.reactnativetwiliophone/lib-main
2020-12-10 11:10:36.981 16811-16811/? D/SoLoader: libreactnativejni.so found on /data/app/net.appworkshop.reactnativetwiliophone-s3ceXwUvc8MsF1TciRIWKA==/lib/x86
2020-12-10 11:10:37.428 16811-16901/? W/tivetwiliophon: Accessing hidden method Landroid/os/WorkSource;->add(I)Z (greylist, reflection, allowed)
2020-12-10 11:10:37.428 16811-16901/? W/tivetwiliophon: Accessing hidden method Landroid/os/WorkSource;->add(ILjava/lang/String;)Z (greylist, reflection, allowed)
2020-12-10 11:10:37.428 16811-16901/? W/tivetwiliophon: Accessing hidden method Landroid/os/WorkSource;->size()I (greylist, reflection, allowed)
2020-12-10 11:10:37.428 16811-16901/? W/tivetwiliophon: Accessing hidden method Landroid/os/WorkSource;->get(I)I (greylist, reflection, allowed)
2020-12-10 11:10:37.428 16811-16901/? W/tivetwiliophon: Accessing hidden method Landroid/os/WorkSource;->getName(I)Ljava/lang/String; (greylist, reflection, allowed)
2020-12-10 11:10:39.344 16811-16908/? I/tivetwiliophon: The ClassLoaderContext is a special shared library.
2020-12-10 11:10:39.429 16811-16908/? I/tivetwiliophon: The ClassLoaderContext is a special shared library.
2020-12-10 11:10:40.728 16811-16907/? W/tivetwiliophon: JNI critical lock held for 33.610ms on Thread[40,tid=16907,Runnable,Thread*=0xbaa7ba00,peer=0x13480200,"mqt_js"]
2020-12-10 11:10:41.682 2042-2885/? I/ActivityTaskManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10680000 pkg=net.appworkshop.reactnativetwiliophone cmp=net.appworkshop.reactnativetwiliophone/.MainActivity} from uid 10139
2020-12-10 11:10:41.683 2042-2885/? W/ActivityTaskManager: Background activity start [callingPackage: net.appworkshop.reactnativetwiliophone; callingUid: 10139; isCallingUidForeground: false; isCallingUidPersistentSystemProcess: false; realCallingUid: 10139; isRealCallingUidForeground: false; isRealCallingUidPersistentSystemProcess: false; originatingPendingIntent: null; isBgStartWhitelisted: false; intent: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10680000 pkg=net.appworkshop.reactnativetwiliophone cmp=net.appworkshop.reactnativetwiliophone/.MainActivity }; callerApp: ProcessRecord{f23fb7b 16811:net.appworkshop.reactnativetwiliophone/u0a139}]
2020-12-10 11:10:41.690 16811-16908/? I/TwilioPhone: Handling message
2020-12-10 11:10:41.691 16811-16908/? D/TwilioPhone: payload: =====
2020-12-10 11:10:41.692 16811-16908/? D/TwilioPhone: twi_message_id = "RUd72...<truncated>"
2020-12-10 11:10:41.692 16811-16908/? D/TwilioPhone: twi_to = "client:Larry"
2020-12-10 11:10:41.692 16811-16908/? D/TwilioPhone: twi_from = "client:quick_start1"
2020-12-10 11:10:41.692 16811-16908/? D/TwilioPhone: twi_account_sid = "AC77...<truncated>"
2020-12-10 11:10:41.692 16811-16908/? D/TwilioPhone: twi_call_sid = "CAdb...<truncated>"
2020-12-10 11:10:41.692 16811-16908/? D/TwilioPhone: twi_message_type = "twilio.voice.call"
2020-12-10 11:10:41.692 16811-16908/? D/TwilioPhone: twi_bridge_token = "eyJ6...<truncated>"
2020-12-10 11:10:43.179 16811-16908/? D/TwilioPhone: Call invite received

=====
2020-12-10 11:11:24.112 16811-16908/? D/TwilioPhone: Cancelled call invite received
=====
cunneen commented 3 years ago

OK I figured out why the killed application doesn't display the incoming call UI. In TwilioPhoneModule.handleMessage() > MessageListener.onCallInvite( ), there's an attempt to send a CallInvite event to the react native context. The corresponding event listener in the react native app is never invoked, and that is what would display the incoming call UI. Exactly why it's not invoked I haven't yet figured out; I suspect the main activity is not being started.

MrHertal commented 3 years ago

Thanks @cunneen for investigating. The screenshot above was indeed taken with app in background (not killed). I got some time today to work on this. I will try another approach for handling background/killed state on Android and will try to not use CallKeep backToForeground, but simply init CallKeep and register necessary listeners.

I will keep you updated.

MrHertal commented 3 years ago

@cunneen I managed to receive incoming calls when app is killed on Android 9, 10, 11 and released a fix: https://github.com/MrHertal/react-native-twilio-phone/releases/tag/v1.3.2

I invite you to test that new version :)

Problem was CallKeep backToForeground that could not wake up the app. I replaced it with a headless initialization of CallKeep followed by event subscriptions.

@skibrit During my tests, I once received the notification without buttons to decline or accept. I think the problem came from event listeners being attached multiple times. I have included a check to remove all listeners before adding them, so it should be good now. Just make sure to call initialize when a high order component is mounted, to avoid calling it multiple times (like on each render).

I close this issue for now. Tell me if the new version still does not work for you and I will reopen it.

cunneen commented 3 years ago

Thanks @MrHertal . It'll be a few days before I can test your fix. I really appreciate your efforts.

GuilhermeLessa commented 10 months ago

@skibrit @MrHertal your manifest settings (i dont know what exaclty of those) helped me to incomings call events, it should be on home page doc of this repo