Closed khurana3192 closed 6 years ago
Ok, so I found the reason, basically when my screen is locked, and if try opening the activity with the incoming fcm notification, onDestroy gets called and destroys the activity. Any suggestions how can I overcome this problem?
@khurana3192 does onNewIntent()
get called at all? Can you share how you have setup the PendingIntent
that gets passed with the Notification
?
@kbagchiGWC Thanks for getting back to me. We are planning to release an update to our Android app that is based on the Twilio Voice SDK. Our customers want a more native like experience where they can directly see a screen to accept or reject call (just like Skype/Whatsapp/Viber/Line etc), instead of clicking on the notification and then the dialog box. Moreover this should also work on the lock screen as well.
As of now, I am successful in opening up an activity in my app and show the accept or reject buttons. It works both when app is in foreground or background. Here's the piece of code which is achieving this. I have modified the notify()
method in VoiceFirebaseMessagingService.java to show an activity whenever onMessageRecived
is called for incoming call notification.
private void notify(CallInvite callInvite, int notificationId) {
String callSid = callInvite.getCallSid();
if (callInvite.getState() == CallInvite.State.PENDING) {
soundPoolManager.playRinging();
System.out.println("Disabling keyguard and accquiring wake lock");
Intent intent = new Intent(this, OnCallActivityNew.class);
intent.setAction(OnCallActivityNew.ACTION_INCOMING_CALL);
intent.putExtra(OnCallActivityNew.INCOMING_CALL_NOTIFICATION_ID, notificationId);
intent.putExtra(OnCallActivityNew.INCOMING_CALL_INVITE, callInvite);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent =
PendingIntent.getActivity(this, notificationId, intent, PendingIntent.FLAG_ONE_SHOT);
/*
* Pass the notification id and call sid to use as an identifier to cancel the
* notification later
*/
Bundle extras = new Bundle();
extras.putInt(NOTIFICATION_ID_KEY, notificationId);
extras.putString(CALL_SID_KEY, callSid);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_call_end_white_24px)
.setContentTitle(getString(R.string.app_name))
.setContentText(callInvite.getFrom() + " is calling.")
.setAutoCancel(true)
.setExtras(extras)
.setContentIntent(pendingIntent)
.setGroup("test_app_notification")
.setOngoing(true)
.setColor(Color.rgb(214, 10, 37));
notificationManager.notify(notificationId, notificationBuilder.build());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtras(extras);
globalintent = intent;
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
startActivity(globalintent);
}
},2000);
} else {
SoundPoolManager.getInstance(this).stopRinging();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
/*
* If the incoming call was cancelled then remove the notification by matching
* it with the call sid from the list of notifications in the notification drawer.
*/
StatusBarNotification[] activeNotifications = notificationManager.getActiveNotifications();
for (StatusBarNotification statusBarNotification : activeNotifications) {
Notification notification = statusBarNotification.getNotification();
Bundle extras = notification.extras;
String notificationCallSid = extras.getString(CALL_SID_KEY);
if (callSid.equals(notificationCallSid)) {
notificationManager.cancel(extras.getInt(NOTIFICATION_ID_KEY));
} else {
sendCallInviteToActivity(callInvite, notificationId);
}
}
} else {
/*
* Prior to Android M the notification manager did not provide a list of
* active notifications so we lazily clear all the notifications when
* receiving a cancelled call.
*
* In order to properly cancel a notification using
* NotificationManager.cancel(notificationId) we should store the call sid &
* notification id of any incoming calls using shared preferences or some other form
* of persistent storage.
*/
notificationManager.cancelAll();
}
}
}
Moreover, in the onCreate()
of the OnCallActivityNew.java I have mentioned the following code.
@Override
protected void onCreate(Bundle savedInstanceState) {
System.out.println("on create of activity is called for oncallactivitynew");
super.onCreate(savedInstanceState);
KeyguardManager kgm = (KeyguardManager)getSystemService(Context.KEYGUARD_SERVICE);
boolean isKeyguardUp = kgm.inKeyguardRestrictedInputMode();
KeyguardManager.KeyguardLock kgl = kgm.newKeyguardLock("OnCallActivityNew");
if(isKeyguardUp){
kgl.disableKeyguard();
isKeyguardUp = false;
}
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "My Tag");
wl.acquire();
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON,
WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
setContentView(R.layout.activity_on_call);
coordinatorLayout = (CoordinatorLayout) fin
..... ///more code below to add listener to different buttons
}
The only problem now is that when the phone is locked, this activity opens and onDestroy() is called and I am unable to show the screen to accept and reject buttons.
The desired behaviour I want is to have a mechanism where one can take calls even on the lock screen just like the apps I have mentioned above.
I know this is a problem which is more related to how Android works, but any help in this regard from you guys will be really appreciated. I am sure people will benefit out from this discussion.
@khurana3192 have you looked at ConnectionService
(https://developer.android.com/reference/android/telecom/ConnectionService.html)?
@kbagchiGWC many questions on Stackoverflow points to ConnectionService
to show native like incoming calls. First of all, the documentation in this regard is not that great. Secondly, this method is not always guaranteed to work on different devices (got to know from Stackoverflow under different posts). Moreover, I think companies like Whatsapp, Skype, Line, Viber are not following the ConnectionService
route.
Is Twilio planning to include the support for this, just like the above said companies? Can you point me in the right direction or a working example apart from that Android developers link?
We don't have a sample for this at the moment but as you've pointed out there are other apps that do this so the support is available on the Android platform. We will consider adding a sample for this in the future but I don't have a timeline for when.
It sounds like your close to a solution. My impression is that the attributes associated with your Activity may be causing the issue. I would review settings associated with https://developer.android.com/guide/topics/manifest/activity-element.html#lmode or https://developer.android.com/reference/android/R.attr.html#configChanges are resulting in onDestroy()
being called.
@idelgado Thanks for considering this request, I am sure if you guys can do the same for your Android SDK, it will really help devs like us to cut down time required to ship a working VOIP app with Twilio. I would love to contribute in any such development if I get success with this problem of mine.
Even if I ensure that onDestroy()
is not called by handling config changes or openinig the activity with a specific mode, bypassing keyguard and showing the in-call ui is not that easy. I think as @kbagchiGWC I need to dig deeper into how ConnectionService
works in Android and show an incoming call ui accordingly.
Again, I am limited by time and was wondering if I can get a working solution to implement the same.
@khurana3192 -- try this orverride this method in your call activity class
@Override //to turn on screen while its lock when call is arriving public void onAttachedToWindow() { Window window = getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); }
get required permissions in manifest
Hey @abhinay-w3bminds
I have added that method and also permissions in manifest. The screen does light up but somehow the activity gets destroyed and doesn't appear on the lock screen
@khurana3192 If you are getting call while screen is awake then check if you are registering broadcast receiver in java class then do it in manifest and then try..
@abhinay-w3bminds are you referring to the registration listener function of Twilio SDK?
@abhinay-w3bminds is there a way I can share my complete code with you after leaving comments so that you can help me better?
@khurana3192 share it on github
@khurana3192, have you found a solution for this or for ConnectionService?
I am still looking for a pre-baked solution to cut down my research time :(
I am also facing the exact same issue, the screen lights up and then the activity gets destroyed. I have already tried all the answers present on SO like setting windows flags, manifest permissions, acquiring wake locks. Nothing seem to work surprisingly. @khurana3192 Any help/ progress from the situation? @abhinay-w3bminds Any other pointers?
@khurana3192 , @chakri1vr1, @rochapablo
We have updated voice-quickstart-android to demonstrate how to enable users to directly see a screen to accept or reject call , instead of clicking on the notification and then the dialog box. This works when the screen is locked as well.
It took us sometime to get to it, apologies for delay. Hope this helps. Please let us know if you have any questions.
The PR with the changes can be found here: https://github.com/twilio/voice-quickstart-android/pull/143
This is awesome. Thanks for the update @kbagchiGWC @idelgado, will try to implement these changes in my current app. I was looking for someone from Twilio team to review our code, as many of our existing users are facing problems around our app. Can this be a possibility?
@khurana3192 Is your code in github? What kind of issues are you having? If you provide details, we will try to help you as much as possible.
@kbagchiGWC The problem that I am facing at the moment - once the activity opens up it gets called again somehow and canels the flow of call. My app compromises of many other features apart from calling. One of the activity that handles an ongoing call is called when I receive an incoming call Invite, but as soon as the call is accepted or answer method is called, the activity is triggered again causing the current operation to be affected. Since my app is being used by more than 3k customers, can I share this with you privately via a gist or something?
@khurana3192 You can send the gist link to my email.
@khurana3192
I am glad that your app is working as expected. Please close the ticket if you don't have further questions. Feel free to open a new issue for any future needs.
@kbagchiGWC Thanks for all your help :) I will be glad to answer here, if anyone is facing this issue or trying to achieve the same thing
Hi @khurana3192 , How did you achieved this functionality? did you end up using connectionService?
@basitsattar We have demonstrated how to achieve this in voice-quickstart-android code. The specific changes you need can be found here.
Give that a try and let me know if you have any questions.
@kbagchiGWC @idelgado during my tests I found out that including this flag:
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
doesn't deliver the UX I wished for.
When the device is locked and it receives a call I want the screen to dim again after a while.
If I add these lines:
// These flags ensure that the activity can be launched when the screen is locked.
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
when the app receives a call the app bypass the lock screen and the screen doesn't keep on.
For my benefit, could you explain why that flag was included. I want to make sure I haven't missed a technical requirement with the implementation
@fabriziomoscon
During our test/research, we concluded that not adding FLAG_TURN_SCREEN_ON
did not guarantee to make the activity visible for some devices. That's why we added the flag. If you want the screen to dim, you can call
window.clearFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
to clear the flag at any point.
Thanks for bringing this up. I see according to https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_TURN_SCREEN_ON, FLAG_TURN_SCREEN_ON
is being deprecated. We will update the quickstart soon.
thanks for the reply @kbagchiGWC
but I was referring to
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
not to
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
@fabriziomoscon Apologies, misread your comment. FLAG_KEEP_SCREEN_ON
is not necessary for the experience you are looking for. I will remove it from the code.
great news thanks
Is this solution for video calls?
@Pastcarand We haven't tested this for Video calls but it's quite possible that it will also work for that use case.
@kbagchiGWC Thanks for all your help :) I will be glad to answer here, if anyone is facing this issue or trying to achieve the same thing
hi. Please am presently building a custom calling app for android am having the same issue please can you help out
Secondly, this method is not always guaranteed to work on different devices (got to know from Stackoverflow under different posts).
Speaking as someone who's worked on inbound call notifications working across multiple handset manufacturers - trying to roll your own is much, much worse than just using ConnectionService. Be prepared to do extensive testing across Samsung devices, in particular. And pay attention to how they behave when they're locked and your app hasn't been launched and you get an inbound FCM message. Then add bluetooth headsets to your test matrix. And don't forget to test when the devices are showing the Samsung low-power always-on lockscreen. Don't forget about the new battery management stuff. (And then finally give up in disgust and just implement a ConnectionService, IMHO.)
Hi, @banshee Your comment is very useful. Do you know if there's any alternative to ConnectionService for API <23?
Not that I know of. We just said 23 is our new minimum version.
Add one more thing to my list - do extensive testing with both native cell calls and your own calls simultaneously. Ordering matters, so test your call + incoming cell call, and vice versa. Test on multiple Samsung devices. Note that Samsung and Pixels will never, under any circumstances, do the same thing. If you don't hate samsung with a burning passion by the time you're done, you're not testing on enough samsung devices. Oh, and if you care, make sure you test on samsung devices that aren't sold in your country. The ones you have a hard time getting are going to have different problems than the ones you already have.
@basitsattar We have demonstrated how to achieve this in voice-quickstart-android code. The specific changes you need can be found here.
Give that a try and let me know if you have any questions.
is it working when the app forcefully killed from multitasking.?
@basitsattar We have demonstrated how to achieve this in voice-quickstart-android code. The specific changes you need can be found here.
Give that a try and let me know if you have any questions.
Actually, VoiceActivity.java file does not exist
I have tried to perform searches in the project with:
There is no trace of lines of code that appear in the PR. What solution exists in the current code?
@banshee I am not getting understand which way is the best to implement calling app like through FCM or ConnectionService. If ConnectionService is good to integrate calling app then Could you please demonstrate the connectionservice example.
Hi @khurana3192 , How did you achieved this functionality? did you end up using connectionService?
Did you implement this by connectionService?
I have added this line of code in my app Window window = getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; for receive call when mobile is locked but when i tried to call is being cancelled automatically.
@khurana3192 can you please explain that how you solved this on your side.
@Ranaamin0322 did you ever find a solution to this? I have the same issue
@khurana3192 pls help if u were able to solve this @banshee as much as i agree with u, but i have used two apps with voip calling - Whatsapp and MS Teams.. both of them doesnt seem to be using ConnectionService
i'm having the same problem too. can't wake the app when caller call using twilio.
Has anyone actually implemented this using ConnectionService?
I'm in the process of trying to implement ConnectionService into twilio-quickstart-android, but I don't want to duplicate work if anyone else has already successfully done this. I'm also open to collaborating with others if they want to help implement ConnectionService with me.
Has anyone actually implemented this using ConnectionService?
I'm in the process of trying to implement ConnectionService into twilio-quickstart-android, but I don't want to duplicate work if anyone else has already successfully done this. I'm also open to collaborating with others if they want to help implement ConnectionService with me.
hi Kody
I have implemented a basic version of ConnectionService. Ready to collab for implementing with twilio.
I am able to open an activity to show the hangup and accept buttons whenever there is an incoming call. But I am still wondering, how I can do this when my keyguard is locked. Any ideas guys?