Trying to prevent or understand issues with incoming call activity

This commit is contained in:
Sylvain Berfini 2020-05-26 20:50:14 +02:00
parent fe8524da14
commit b6934e02fd
10 changed files with 106 additions and 30 deletions

View file

@ -101,14 +101,11 @@
<activity android:name=".activities.call.CallActivity" <activity android:name=".activities.call.CallActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
android:showWhenLocked="true"
android:supportsPictureInPicture="true" /> android:supportsPictureInPicture="true" />
<activity android:name=".activities.call.IncomingCallActivity" <activity android:name=".activities.call.IncomingCallActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
android:noHistory="true" android:noHistory="true" />
android:showWhenLocked="true"
android:turnScreenOn="true" />
<activity android:name=".activities.call.OutgoingCallActivity" <activity android:name=".activities.call.OutgoingCallActivity"
android:launchMode="singleTop" android:launchMode="singleTop"

View file

@ -49,6 +49,7 @@ class CallActivity : ProximitySensorActivity() {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
Compatibility.setShowWhenLocked(this, true) Compatibility.setShowWhenLocked(this, true)
Compatibility.setTurnScreenOn(this, true)
binding = DataBindingUtil.setContentView(this, R.layout.call_activity) binding = DataBindingUtil.setContentView(this, R.layout.call_activity)
binding.lifecycleOwner = this binding.lifecycleOwner = this

View file

@ -22,6 +22,7 @@ package org.linphone.activities.call
import android.annotation.TargetApi import android.annotation.TargetApi
import android.app.KeyguardManager import android.app.KeyguardManager
import android.content.Context import android.content.Context
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.WindowManager import android.view.WindowManager
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
@ -47,22 +48,16 @@ class IncomingCallActivity : GenericActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
Compatibility.setShowWhenLocked(this, true)
Compatibility.setTurnScreenOn(this, true) Compatibility.setTurnScreenOn(this, true)
Compatibility.setShowWhenLocked(this, true)
Compatibility.requestDismissKeyguard(this)
binding = DataBindingUtil.setContentView(this, R.layout.call_incoming_activity) binding = DataBindingUtil.setContentView(this, R.layout.call_incoming_activity)
binding.lifecycleOwner = this binding.lifecycleOwner = this
var incomingCall: Call? = null var incomingCall: Call? = findIncomingCall()
for (call in coreContext.core.calls) {
if (call.state == Call.State.IncomingReceived ||
call.state == Call.State.IncomingEarlyMedia) {
incomingCall = call
}
}
if (incomingCall == null) { if (incomingCall == null) {
Log.e("[Incoming Call] Couldn't find call in state Incoming") Log.e("[Incoming Call Activity] Couldn't find call in state Incoming")
finish() finish()
return return
} }
@ -75,6 +70,14 @@ class IncomingCallActivity : GenericActivity() {
viewModel.callEndedEvent.observe(this, Observer { viewModel.callEndedEvent.observe(this, Observer {
it.consume { it.consume {
Log.i("[Incoming Call Activity] Call ended, finish activity")
finish()
}
})
viewModel.callConnectedEvent.observe(this, Observer {
it.consume {
Log.i("[Incoming Call Activity] Call connected, finish activity")
finish() finish()
} }
}) })
@ -89,15 +92,25 @@ class IncomingCallActivity : GenericActivity() {
} }
} }
override fun onResume() {
super.onResume()
var incomingCall: Call? = findIncomingCall()
if (incomingCall == null) {
Log.e("[Incoming Call Activity] Couldn't find call in state Incoming")
finish()
}
}
@TargetApi(Version.API23_MARSHMALLOW_60) @TargetApi(Version.API23_MARSHMALLOW_60)
private fun checkPermissions() { private fun checkPermissions() {
val permissionsRequiredList = arrayListOf<String>() val permissionsRequiredList = arrayListOf<String>()
if (!PermissionHelper.get().hasRecordAudioPermission()) { if (!PermissionHelper.get().hasRecordAudioPermission()) {
Log.i("[Incoming Call] Asking for RECORD_AUDIO permission") Log.i("[Incoming Call Activity] Asking for RECORD_AUDIO permission")
permissionsRequiredList.add(android.Manifest.permission.RECORD_AUDIO) permissionsRequiredList.add(android.Manifest.permission.RECORD_AUDIO)
} }
if (viewModel.call.currentParams.videoEnabled() && !PermissionHelper.get().hasCameraPermission()) { if (viewModel.call.currentParams.videoEnabled() && !PermissionHelper.get().hasCameraPermission()) {
Log.i("[Incoming Call] Asking for CAMERA permission") Log.i("[Incoming Call Activity] Asking for CAMERA permission")
permissionsRequiredList.add(android.Manifest.permission.CAMERA) permissionsRequiredList.add(android.Manifest.permission.CAMERA)
} }
if (permissionsRequiredList.isNotEmpty()) { if (permissionsRequiredList.isNotEmpty()) {
@ -106,4 +119,14 @@ class IncomingCallActivity : GenericActivity() {
requestPermissions(permissionsRequired, 0) requestPermissions(permissionsRequired, 0)
} }
} }
private fun findIncomingCall(): Call? {
for (call in coreContext.core.calls) {
if (call.state == Call.State.IncomingReceived ||
call.state == Call.State.IncomingEarlyMedia) {
return call
}
}
return null
}
} }

View file

@ -49,17 +49,9 @@ class OutgoingCallActivity : ProximitySensorActivity() {
binding = DataBindingUtil.setContentView(this, R.layout.call_outgoing_activity) binding = DataBindingUtil.setContentView(this, R.layout.call_outgoing_activity)
binding.lifecycleOwner = this binding.lifecycleOwner = this
var outgoingCall: Call? = null var outgoingCall: Call? = findOutgoingCall()
for (call in coreContext.core.calls) {
if (call.state == Call.State.OutgoingInit ||
call.state == Call.State.OutgoingProgress ||
call.state == Call.State.OutgoingRinging) {
outgoingCall = call
}
}
if (outgoingCall == null) { if (outgoingCall == null) {
Log.e("[Outgoing Call] Couldn't find call in state Outgoing") Log.e("[Outgoing Call Activity] Couldn't find call in state Outgoing")
finish() finish()
return return
} }
@ -91,6 +83,14 @@ class OutgoingCallActivity : ProximitySensorActivity() {
viewModel.callEndedEvent.observe(this, Observer { viewModel.callEndedEvent.observe(this, Observer {
it.consume { it.consume {
Log.i("[Outgoing Call Activity] Call ended, finish activity")
finish()
}
})
viewModel.callConnectedEvent.observe(this, Observer {
it.consume {
Log.i("[Outgoing Call Activity] Call connected, finish activity")
finish() finish()
} }
}) })
@ -100,15 +100,25 @@ class OutgoingCallActivity : ProximitySensorActivity() {
} }
} }
override fun onResume() {
super.onResume()
var outgoingCall: Call? = findOutgoingCall()
if (outgoingCall == null) {
Log.e("[Outgoing Call Activity] Couldn't find call in state Outgoing")
finish()
}
}
@TargetApi(Version.API23_MARSHMALLOW_60) @TargetApi(Version.API23_MARSHMALLOW_60)
private fun checkPermissions() { private fun checkPermissions() {
val permissionsRequiredList = arrayListOf<String>() val permissionsRequiredList = arrayListOf<String>()
if (!PermissionHelper.get().hasRecordAudioPermission()) { if (!PermissionHelper.get().hasRecordAudioPermission()) {
Log.i("[Outgoing Call] Asking for RECORD_AUDIO permission") Log.i("[Outgoing Call Activity] Asking for RECORD_AUDIO permission")
permissionsRequiredList.add(android.Manifest.permission.RECORD_AUDIO) permissionsRequiredList.add(android.Manifest.permission.RECORD_AUDIO)
} }
if (viewModel.call.currentParams.videoEnabled() && !PermissionHelper.get().hasCameraPermission()) { if (viewModel.call.currentParams.videoEnabled() && !PermissionHelper.get().hasCameraPermission()) {
Log.i("[Outgoing Call] Asking for CAMERA permission") Log.i("[Outgoing Call Activity] Asking for CAMERA permission")
permissionsRequiredList.add(android.Manifest.permission.CAMERA) permissionsRequiredList.add(android.Manifest.permission.CAMERA)
} }
if (permissionsRequiredList.isNotEmpty()) { if (permissionsRequiredList.isNotEmpty()) {
@ -117,4 +127,15 @@ class OutgoingCallActivity : ProximitySensorActivity() {
requestPermissions(permissionsRequired, 0) requestPermissions(permissionsRequired, 0)
} }
} }
private fun findOutgoingCall(): Call? {
for (call in coreContext.core.calls) {
if (call.state == Call.State.OutgoingInit ||
call.state == Call.State.OutgoingProgress ||
call.state == Call.State.OutgoingRinging) {
return call
}
}
return null
}
} }

View file

@ -50,6 +50,10 @@ open class CallViewModel(val call: Call) : GenericContactViewModel(call.remoteAd
MutableLiveData<Event<Boolean>>() MutableLiveData<Event<Boolean>>()
} }
val callConnectedEvent: MutableLiveData<Event<Boolean>> by lazy {
MutableLiveData<Event<Boolean>>()
}
private val listener = object : CallListenerStub() { private val listener = object : CallListenerStub() {
override fun onStateChanged(call: Call, state: Call.State, message: String) { override fun onStateChanged(call: Call, state: Call.State, message: String) {
if (call != this@CallViewModel.call) return if (call != this@CallViewModel.call) return
@ -62,6 +66,8 @@ open class CallViewModel(val call: Call) : GenericContactViewModel(call.remoteAd
if (state == Call.State.Error) { if (state == Call.State.Error) {
Log.e("[Call View Model] Error state reason is ${call.reason}") Log.e("[Call View Model] Error state reason is ${call.reason}")
} }
} else if (call.state == Call.State.Connected) {
callConnectedEvent.value = Event(true)
} }
} }
} }

View file

@ -169,5 +169,9 @@ class Api21Compatibility {
activity.window.clearFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) activity.window.clearFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
} }
} }
fun requestDismissKeyguard(activity: Activity) {
activity.window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD)
}
} }
} }

View file

@ -21,6 +21,7 @@ package org.linphone.compatibility
import android.annotation.TargetApi import android.annotation.TargetApi
import android.app.* import android.app.*
import android.content.Context
@TargetApi(27) @TargetApi(27)
class Api27Compatibility { class Api27Compatibility {
@ -32,5 +33,10 @@ class Api27Compatibility {
fun setTurnScreenOn(activity: Activity, enable: Boolean) { fun setTurnScreenOn(activity: Activity, enable: Boolean) {
activity.setTurnScreenOn(enable) activity.setTurnScreenOn(enable)
} }
fun requestDismissKeyguard(activity: Activity) {
val keyguardManager = activity.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
keyguardManager.requestDismissKeyguard(activity, null)
}
} }
} }

View file

@ -64,6 +64,14 @@ class Compatibility {
} }
} }
fun requestDismissKeyguard(activity: Activity) {
if (Version.sdkStrictlyBelow(Version.API27_OREO_81)) {
Api21Compatibility.requestDismissKeyguard(activity)
} else {
Api27Compatibility.requestDismissKeyguard(activity)
}
}
/* Notifications */ /* Notifications */
fun createNotificationChannels( fun createNotificationChannels(

View file

@ -30,7 +30,6 @@ import android.telephony.PhoneStateListener
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import android.view.* import android.view.*
import java.io.File import java.io.File
import java.util.*
import kotlin.math.abs import kotlin.math.abs
import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.activities.call.CallActivity import org.linphone.activities.call.CallActivity
@ -435,6 +434,7 @@ class CoreContext(val context: Context, coreConfig: Config) {
/* Start call related activities */ /* Start call related activities */
private fun onIncomingReceived() { private fun onIncomingReceived() {
Log.i("[Context] Starting IncomingCallActivity")
val intent = Intent(context, IncomingCallActivity::class.java) val intent = Intent(context, IncomingCallActivity::class.java)
// This flag is required to start an Activity from a Service context // This flag is required to start an Activity from a Service context
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
@ -442,6 +442,7 @@ class CoreContext(val context: Context, coreConfig: Config) {
} }
private fun onOutgoingStarted() { private fun onOutgoingStarted() {
Log.i("[Context] Starting OutgoingCallActivity")
val intent = Intent(context, OutgoingCallActivity::class.java) val intent = Intent(context, OutgoingCallActivity::class.java)
// This flag is required to start an Activity from a Service context // This flag is required to start an Activity from a Service context
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
@ -449,6 +450,7 @@ class CoreContext(val context: Context, coreConfig: Config) {
} }
private fun onCallStarted() { private fun onCallStarted() {
Log.i("[Context] Starting CallActivity")
val intent = Intent(context, CallActivity::class.java) val intent = Intent(context, CallActivity::class.java)
// This flag is required to start an Activity from a Service context // This flag is required to start an Activity from a Service context
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)

View file

@ -343,6 +343,11 @@ class NotificationsManager(private val context: Context) {
val address = call.remoteAddress.asStringUriOnly() val address = call.remoteAddress.asStringUriOnly()
val notifiable = getNotifiableForCall(call) val notifiable = getNotifiableForCall(call)
if (notifiable.notificationId == currentForegroundServiceNotificationId) {
Log.w("[Notifications Manager] Incoming call notification already displayed by foreground service, skipping")
return
}
val contact: Contact? = coreContext.contactsManager.findContactByAddress(call.remoteAddress) val contact: Contact? = coreContext.contactsManager.findContactByAddress(call.remoteAddress)
val pictureUri = contact?.getContactThumbnailPictureUri() val pictureUri = contact?.getContactThumbnailPictureUri()
val roundPicture = ImageUtils.getRoundBitmapFromUri(context, pictureUri) val roundPicture = ImageUtils.getRoundBitmapFromUri(context, pictureUri)
@ -380,10 +385,13 @@ class NotificationsManager(private val context: Context) {
.addAction(getCallAnswerAction(notifiable.notificationId)) .addAction(getCallAnswerAction(notifiable.notificationId))
.setCustomHeadsUpContentView(notificationLayoutHeadsUp) .setCustomHeadsUpContentView(notificationLayoutHeadsUp)
.build() .build()
notify(notifiable.notificationId, notification)
if (useAsForeground) { if (useAsForeground) {
Log.i("[Notifications Manager] Notifying incoming call notification for foreground service")
startForeground(notifiable.notificationId, notification) startForeground(notifiable.notificationId, notification)
} else {
Log.i("[Notifications Manager] Notifying incoming call notification")
notify(notifiable.notificationId, notification)
} }
} }