react-native-twilio-programmable-voice icon indicating copy to clipboard operation
react-native-twilio-programmable-voice copied to clipboard

feat: Android Twilio SDK 5.4.2

Open fabriziomoscon opened this issue 4 years ago • 30 comments

Ported Twilio quickstart changes up to this point https://github.com/twilio/voice-quickstart-android/commit/e3db03fac386ae18d3790a52dbd423ead7234ab3

  • [x] notification for incoming call when the app is in the background

  • [x] implement Android v5

  • [x] test making a call

  • [x] test incoming call, when app in foreground

  • [x] test incoming call, when app in background

  • [x] test incoming call, when app is closed

  • [x] test after a call invite is cancelled, opening the JS app doesn't trigger the incoming call screen

  • [x] cleanup XML resources

  • [x] incoming notifications when the device is locked

  • [x] correctly cleanup a CALL_INVITE after answering or missed, currently the second time the app is stuck with this log:

  • [x] Error when receiving a call and the app is closed

2020-11-15 12:53:28.746 32167-32167/? W/GCM: broadcast intent callback: result=CANCELLED forIntent { act=com.google.android.c2dm.intent.RECEIVE flg=0x10000000 pkg=com.hoxfon.HoxFon.DEV.debug (has extras) }
  • [x] Ensure that issue #77 is resolved: In call dialpad not accessible when the call is answered from the lock screen

  • [x] add intent to call in progress notification to bring the app to the foreground

  • [x] write migration instruction in the README

Known issues:

  • [x] Call invite heads-up notification are not auto cancelled. This issue happens when a call is received and the screen is locked or the screen in unlocked, but the app is in the background. The heads-up notification service is started. If the user taps on the notification full screen content (not reject nor answer button), and then accepts the call from JS, at the end of the call the heads-up notification won't be removed, because there is no push notification for end call, just for call invite cancelled by the caller. I don't know how to solve this issue, because endForeground() can only be called by the service and all the user interactions from JS end are handled by the VoiceModule. At the same time full screen content is needed to show the JS incoming call screen when the phone is locked, therefore it can't be removed.

Reported bugs:

  • [x] getLaunchOptions() crashes upon the first app launch: https://github.com/hoxfon/react-native-twilio-programmable-voice/pull/164#issuecomment-757965249 (not able to reproduce)
  • [ ] check microphone permissions: https://github.com/hoxfon/react-native-twilio-programmable-voice/pull/164#issuecomment-753997031
  • [x] check fullscreen intent https://github.com/hoxfon/react-native-twilio-programmable-voice/pull/164#issuecomment-753997031
  • [x] If I invoke call screen on app kill with device locked then accept call using TwilioVoice.accept() still the notification is showing after the call connect - Android version (8 , 9, 10 , 11): https://github.com/hoxfon/react-native-twilio-programmable-voice/pull/164#issuecomment-753994599

fabriziomoscon avatar Nov 15 '20 13:11 fabriziomoscon

@fabriziomoscon is there any reason why you are upgrading to 5.0.1 and not to 5.6.0? I'm asking since #39 depends on Android SDK being 5.3.0 or newer.

fmonsalvo avatar Nov 17 '20 13:11 fmonsalvo

@fmonsalvo I am going through all commits here: https://github.com/twilio/voice-quickstart-android/commits one by one and port them

fabriziomoscon avatar Nov 19 '20 00:11 fabriziomoscon

Perfect, just wanted to know the rationale. I appreciate all your hard work!

fmonsalvo avatar Nov 20 '20 13:11 fmonsalvo

@fabriziomoscon Hi. I have updated the Android Twilio SDK 5.0.2 code from this branch (458b0d4) and still facing same issue for incoming call.

Samsritha1596 avatar Dec 21 '20 15:12 Samsritha1596

@Samsritha1596 please refer to the above checklist to see the completion stage of this PR. Currently test incoming call, when app is closed is unchecked. Note that this use case is one of the known issue with the current master branch, which PR aims to solve.

fabriziomoscon avatar Dec 21 '20 18:12 fabriziomoscon

@Samsritha1596 please try to use this commit: 88f4f7301aebc36c89c07ba85decd5b7b6ee0a1c and let me know if you can receive calls when the app is killed.

fabriziomoscon avatar Dec 21 '20 19:12 fabriziomoscon

@fabriziomoscon Incoming call is not receiving when app is killed and also no events were triggered

Here is the version details:

"react-native": "0.61.5", "react-native-twilio-programmable-voice": "^4.3.0", "react-native-push-notification": "^6.1.3",

Please find the attached screenshot for app is killed

Screenshot 2020-12-22 at 12 36 55 PM

Samsritha1596 avatar Dec 22 '20 07:12 Samsritha1596

@fabriziomoscon Any update ?

Samsritha1596 avatar Dec 26 '20 05:12 Samsritha1596

You are not using this PR branch

"react-native-twilio-programmable-voice": "^4.3.0"

Please use:

"react-native-twilio-programmable-voice": "https://github.com/hoxfon/react-native-twilio-programmable-voice#feat/twilio-android-sdk-5",

fabriziomoscon avatar Dec 26 '20 20:12 fabriziomoscon

@fabriziomoscon Receives heads-up notification when app is killed and background without ringing and does not trigger any event

Samsritha1596 avatar Dec 28 '20 14:12 Samsritha1596

@Samsritha1596

Receives heads-up notification when app is killed and background

This is the correct behaviour

without ringing

I don't know if the limitation for background services in Android 10 allow to ring, because they rely on the sound the user sets for notifications

does not trigger any event

This is right, because the JS app is not started, it can't deliver any event. Only tapping on ACCEPT will start the app and deliver the event to JS

fabriziomoscon avatar Dec 29 '20 10:12 fabriziomoscon

@fabriziomoscon Behaves the same way after adding USE_FULL_SCREEN_INTENT

Samsritha1596 avatar Dec 29 '20 13:12 Samsritha1596

@Samsritha1596 Please retry now, note that I pushed forced new commits.

fabriziomoscon avatar Dec 29 '20 20:12 fabriziomoscon

@fabriziomoscon Screen does not invoke automatically when device is locked

Samsritha1596 avatar Dec 30 '20 17:12 Samsritha1596

I found an issue with receiving call in the background when the app is GONE (appImportance 1000). It seems that on my device (OnePlus 6), an activity is started on background whilst the device is locked. Whereas is not starting when the device is not locked.

19:39:24.417 18688-18769/<MY_APP> D/RNTwilioVoice: Bundle data: {twi_account_sid=xxx, twi_to=client:xxx, twi_bridge_token=xxx, twi_message_type=twilio.voice.call, twi_call_sid=xxx, twi_message_id=xxx, twi_from=xxx}
19:39:24.731 18688-18688/<MY_APP> D/RNTwilioVoice: context: null. appImportance = 1000
19:39:24.731 18688-18688/<MY_APP> D/RNTwilioVoice: Background
19:39:24.752 18688-18688/<MY_APP> D/RNTwilioVoice: onStartCommand() intent: Intent { act=ACTION_INCOMING_CALL cmp=<MY_APP>/com.hoxfon.react.RNTwilioVoice.IncomingCallNotificationService (has extras) }, flags: 0
19:39:24.753 18688-18688/<MY_APP> D/RNTwilioVoice: setCallInProgressNotification()
19:39:24.753 18688-18688/<MY_APP> I/RNTwilioVoice: app is NOT visible.
19:39:24.818 18688-18688/<MY_APP> D/RNTwilioVoice: sendCallInviteToActivity(). Android SDK: 29 app visible: false
19:39:24.885 18688-18688/<MY_APP> D/RNTwilioVoice: sendCallInviteToActivity(). DO NOTHING
19:39:24.939 1322-5062/? D/OemSceneCallBlock: isCallBlockedWithUidIntent { act=com.hoxfon.react.RNTwilioVoice.ACTION_INCOMING_CALL flg=0x4000000 cmp=<MY_APP>/com.hoxfon.MainActivity (has extras) }, ResolveInfo{1c0c12d <MY_APP>/com.hoxfon.MainActivity m=0x0}, false
19:39:24.940 1322-5062/? I/ActivityTaskManager: START u0 {act=com.hoxfon.react.RNTwilioVoice.ACTION_INCOMING_CALL flg=0x4000000 cmp=<MY_APP>/com.hoxfon.MainActivity (has extras)} from uid 10469 pid -1
19:39:24.941 1322-5062/? W/ActivityTaskManager: startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: Intent { act=com.hoxfon.react.RNTwilioVoice.ACTION_INCOMING_CALL flg=0x4000000 cmp=<MY_APP>/com.hoxfon.MainActivity (has extras) }
19:39:29.619 18688-18883/<MY_APP> D/RNTwilioVoice: initWithAccessToken()
19:39:29.620 18688-18883/<MY_APP> I/RNTwilioVoice: Registering with FCM

Could anybody try this scenario and verify whether this is a device specific bug?

fabriziomoscon avatar Jan 02 '21 20:01 fabriziomoscon

@fabriziomoscon Yes.. TwilioVoice.getCallInvite() gets called when the device is locked but it does not unlock the device automatically...No activity invoke when app is in background and app closed.. only the connectionDidConnect invoked on answering call. I have tested in samsung galaxy m11 device

If I invoke call screen on app kill with device locked then accept call using TwilioVoice.accept() still the notification is showing after the call connect - Android version (8 , 9, 10 , 11)

2021-01-06 18 19 24

Samsritha1596 avatar Jan 04 '21 14:01 Samsritha1596

@fabriziomoscon How to handle microphone permission on app background and closed if we denied permission and no events were triggered. Here I need to ask permission

Notification full screen intent also not working

TwilioVoice.accept() is not working when I receive call from background without device lock. But it's working background with lock.

Error log - 2021-01-08 12:44:52.265 26753-27024/com.ternster D/RNTwilioVoice: sendEvent callInviteCancelled params null

Screenshot 2021-01-07 at 6 53 49 PM

Samsritha1596 avatar Jan 04 '21 14:01 Samsritha1596

@fabriziomoscon I can also confirm that when the device is locked no activity is launched and the device just starts ringing on a blank screen.

salman-pixarsart avatar Jan 06 '21 11:01 salman-pixarsart

@fabriziomoscon Any solution to clear heads up notification after call end ?

Samsritha1596 avatar Jan 09 '21 10:01 Samsritha1596

After the fresh installation on the android device. App crashes the first time but after that, if we reopen the app, It starts functioning normally and doesn't crash. After debugging I'm able to get these logs

Android Studio Logs

2021-01-11 18:38:05.343 20282-20282/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.free.myapp, PID: 20282
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.free.popup_automessenger/com.free.myapp.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.hashCode()' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2957)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6944)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.hashCode()' on a null object reference
        at com.free.popup_automessenger.MainActivity$1.getLaunchOptions(MainActivity.java:37)
        at com.facebook.react.ReactActivityDelegate.onCreate(ReactActivityDelegate.java:78)
        at com.facebook.react.ReactActivity.onCreate(ReactActivity.java:45)
        at android.app.Activity.performCreate(Activity.java:7183)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2910)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032) 
        at android.app.ActivityThread.-wrap11(Unknown Source:0) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696) 
        at android.os.Handler.dispatchMessage(Handler.java:105) 
        at android.os.Looper.loop(Looper.java:164) 
        at android.app.ActivityThread.main(ActivityThread.java:6944) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374) 

Code which causing this issue ( at MainActivity.java:37 - getLaunchOptions )

package com.free.myapp;
import android.content.Intent;
import android.os.Bundle;

import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.hoxfon.react.RNTwilioVoice.Constants;

import com.facebook.react.ReactActivity;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;

public class MainActivity extends ReactActivity {

  /**
   * Returns the name of the main component registered from JavaScript. This is used to schedule
   * rendering of the component.
   */
  @Override
  protected String getMainComponentName() {
    return "popup_automessenger";
  }

  @Override
  protected ReactActivityDelegate createReactActivityDelegate() {
    return new ReactActivityDelegate(this, getMainComponentName()) {
      @Override
      protected ReactRootView createRootView() {
        return new RNGestureHandlerEnabledRootView(MainActivity.this);
      }
      @Override
      protected Bundle getLaunchOptions() {
        Bundle initialProperties = new Bundle();
        Intent intent = this.getPlainActivity().getIntent();
        if (intent == null) {
          return initialProperties;
        }
        switch (intent.getAction()) {.      // This is line 37 
          case Constants.ACTION_INCOMING_CALL_NOTIFICATION:
            Bundle callInviteBundle = new Bundle();
            callInviteBundle.putString(Constants.CALL_SID, intent.getStringExtra(Constants.CALL_SID));
            callInviteBundle.putString(Constants.CALL_FROM, intent.getStringExtra(Constants.CALL_FROM));
            callInviteBundle.putString(Constants.CALL_TO, intent.getStringExtra(Constants.CALL_TO));
            initialProperties.putBundle(Constants.CALL_INVITE_KEY, callInviteBundle);
            break;

          case Constants.ACTION_ACCEPT:
            Bundle callBundle = new Bundle();
            callBundle.putString(Constants.CALL_SID, intent.getStringExtra(Constants.CALL_SID));
            callBundle.putString(Constants.CALL_FROM, intent.getStringExtra(Constants.CALL_FROM));
            callBundle.putString(Constants.CALL_TO, intent.getStringExtra(Constants.CALL_TO));
            callBundle.putString(Constants.CALL_STATE, Constants.CALL_STATE_CONNECTED);
            initialProperties.putBundle(Constants.CALL_KEY, callBundle);
            break;
        }
        return initialProperties;
      }
    };
  }

}
 

@Samsritha1596 Are you also experiencing this issue?

@fabriziomoscon If you could take a look at this that will be really helpful.

salman-pixarsart avatar Jan 11 '21 13:01 salman-pixarsart

@salman-pixarsart No, i didn't face this issue

@fabriziomoscon Any updates to clear heads up notification after call end ?

Samsritha1596 avatar Jan 30 '21 07:01 Samsritha1596

Thank you guys for testing. For all reported bugs that don't require further clarification, I have created a checkbox in the PR description. I suggest that I provide fixes for those before we start discussing the issues I didn't list.

fabriziomoscon avatar Jan 30 '21 12:01 fabriziomoscon

@salman-pixarsart Previously, in order to launch the app when receiving a call, the flow was:

  1. this module would launch the app normally
  2. the JS would always request the module whether there were incoming calls
  3. if there where any incoming call request the module would use an event to communicate with JS the incoming call parameters
  4. the JS would listen to the event and launch the view with the appropriate incoming call answer/reject controls.

This loop was long and prone to race conditions in case the event was fired before the root view in JS were completely initialised.

This version replaces the previous flow by using getLaunchOptions() to pass initial properties from native to JS when receiving a call as explained here: https://reactnative.dev/docs/communication-android To check for properties I use an Android's intent.

The crash you reported here https://github.com/hoxfon/react-native-twilio-programmable-voice/pull/164#issuecomment-757965249 is caused by hashCode() called on null:

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.hashCode()' on a null object reference
        at com.free.popup_automessenger.MainActivity$1.getLaunchOptions(MainActivity.java:37)

However, this module has checks for intent not null:

        Intent intent = getCurrentActivity().getIntent();
        if (intent == null) {
            return;
        }
        int currentCallInviteIntent = intent.hashCode();

I am not able to reproduce your error. And I am not really able to understand which hashCode() generated this FATAL ERROR. The issue might be with a specific implementation of your app `com.free.popup_automessenger. My suggest would be:

  1. check whether your app MainActivity class needs you to override protected void onCreate(Bundle savedInstanceState)
  2. look for hashCode() in your app's code
  3. to receive more help you could: open an issue (to allow me to focus on that), with the RN version you are using, a video for the crash in the simulator and the logs. And include the logs line before and after the crash.

Thank you for testing.

fabriziomoscon avatar Jan 31 '21 12:01 fabriziomoscon

@Samsritha1596 @salman-pixarsart @jdegger I have added a commit to handle call invites when the phone is locked. Please test and tell me if it fixes a few issues reported above. Note that I changed the PR description to add know issues.

fabriziomoscon avatar Jan 31 '21 18:01 fabriziomoscon

@salman-pixarsart Previously, in order to launch the app when receiving a call, the flow was:

  1. this module would launch the app normally
  2. the JS would always request the module whether there were incoming calls
  3. if there where any incoming call request the module would use an event to communicate with JS the incoming call parameters
  4. the JS would listen to the event and launch the view with the appropriate incoming call answer/reject controls.

This loop was long and prone to race conditions in case the event was fired before the root view in JS were completely initialised.

This version replaces the previous flow by using getLaunchOptions() to pass initial properties from native to JS when receiving a call as explained here: https://reactnative.dev/docs/communication-android To check for properties I use an Android's intent.

The crash you reported here #164 (comment) is caused by hashCode() called on null:

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.String.hashCode()' on a null object reference
        at com.free.popup_automessenger.MainActivity$1.getLaunchOptions(MainActivity.java:37)

However, this module has checks for intent not null:

        Intent intent = getCurrentActivity().getIntent();
        if (intent == null) {
            return;
        }
        int currentCallInviteIntent = intent.hashCode();

I am not able to reproduce your error. And I am not really able to understand which hashCode() generated this FATAL ERROR. The issue might be with a specific implementation of your app `com.free.popup_automessenger. My suggest would be:

  1. check whether your app MainActivity class needs you to override protected void onCreate(Bundle savedInstanceState)
  2. look for hashCode() in your app's code
  3. to receive more help you could: open an issue (to allow me to focus on that), with the RN version you are using, a video for the crash in the simulator, and the logs. And include the logs line before and after the crash.

Thank you for testing.

@fabriziomoscon I'm able to solve this by adding a couple of lines in your code in the main activity of my app. What I'm doing is just verifying if the intent's action is null or not. If null just return the initial properties.

      protected Bundle getLaunchOptions() {
        Bundle initialProperties = new Bundle();
        Intent intent = this.getPlainActivity().getIntent();
        if (intent == null || intent.getAction() == null) {
           return initialProperties;
        }
        switch (intent.getAction()) {
          case Constants.ACTION_INCOMING_CALL_NOTIFICATION:
            Bundle callInviteBundle = new Bundle();
            callInviteBundle.putString(Constants.CALL_SID, intent.getStringExtra(Constants.CALL_SID));
            callInviteBundle.putString(Constants.CALL_FROM, intent.getStringExtra(Constants.CALL_FROM));
            callInviteBundle.putString(Constants.CALL_TO, intent.getStringExtra(Constants.CALL_TO));
            initialProperties.putBundle(Constants.CALL_INVITE_KEY, callInviteBundle);
            break;

          case Constants.ACTION_ACCEPT:
            Bundle callBundle = new Bundle();
            callBundle.putString(Constants.CALL_SID, intent.getStringExtra(Constants.CALL_SID));
            callBundle.putString(Constants.CALL_FROM, intent.getStringExtra(Constants.CALL_FROM));
            callBundle.putString(Constants.CALL_TO, intent.getStringExtra(Constants.CALL_TO));
            callBundle.putString(Constants.CALL_STATE, Constants.CALL_STATE_CONNECTED);
            initialProperties.putBundle(Constants.CALL_KEY, callBundle);
            break;
        }
        return initialProperties;
      }
    };

Also replacing below code in onHostResume() in TwilioVoiceModule.java

        if (intent == null) {
            return;
        }

with

     if (intent == null || intent.getAction() == null) {
           return
            }

Thank you for your response.

salman-pixarsart avatar Feb 01 '21 07:02 salman-pixarsart

@salman-pixarsart I see. That means that sometimes even if intent is not null the action can be null? Is your fix related to this other PR: https://github.com/hoxfon/react-native-twilio-programmable-voice/pull/186/files ?

fabriziomoscon avatar Feb 04 '21 09:02 fabriziomoscon

@fabriziomoscon Yes it is related to that PR. On initial install an intent exist to invoke the app but the intent's action is null. That's why it was causing app crash on initial install.

salman-pixarsart avatar Feb 05 '21 20:02 salman-pixarsart

Hi @fabriziomoscon! I've prepared updates to this branch incl. unregistartion for Android/IOS, and I also solved an issue with "Call invite heads-up notification are not auto cancelled". Can we contact somehow to include those changes to #164 PR?

ro-mgh avatar Apr 22 '21 11:04 ro-mgh

Hello, thanks for make this library update. I've found some issues on getAudioDevices and getSelectedAudioDevice, it returning undefined, apparently the result is not returned on method in index.js, so i make changes like this:

async getAudioDevices() {
    if (Platform.OS === IOS) {
        return
    }
    return await TwilioVoice.getAudioDevices()
},
    
async getSelectedAudioDevice() {
    if (Platform.OS === IOS) {
        return
    }
    return await TwilioVoice.getSelectedAudioDevice()
},

I also make change on method selectAudioDevice in TwilioVoiceModule.java, so when user send null param, audioSwitch will select a device automatically based on the following priority: BluetoothHeadset -> WiredHeadset -> Earpiece -> Speakerphone

@ReactMethod
public void selectAudioDevice(String name) {
    if (name != null) {
        AudioDevice selected = availableAudioDevices.get(name);
        if (selected == null) {
            return;
        }
        audioSwitch.selectDevice(selected);
    } else {
        audioSwitch.selectDevice(null);
    }
}

Also please consider to bring back method setSpeakerPhone on android, with audioSwitch we can make something like this:

@ReactMethod
public void setSpeakerPhone(Boolean value) {
  if (value) {
    AudioDevice speakerphoneDevice = availableAudioDevices.get("Speakerphone");
      if (speakerphoneDevice != null) {
          audioSwitch.selectDevice(speakerphoneDevice);
      }
  } else {
      audioSwitch.selectDevice(null);
  }
}

adyra avatar Aug 27 '21 04:08 adyra

Android 12 support + setSpeaker functionality: https://github.com/hoxfon/react-native-twilio-programmable-voice/issues/211#issuecomment-1165048758

julien9999 avatar Jun 24 '22 00:06 julien9999