Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ configurations.configureEach {
}

dependencies {
implementation("androidx.core:core-telecom:1.0.0")
implementation("androidx.media3:media3-session:1.11.1")
kapt("org.jetbrains.kotlin:kotlin-metadata-jvm:$kotlinVersion")
implementation("androidx.room:room-testing-android:$roomVersion")
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL" />

<uses-permission
android:name="android.permission.USE_CREDENTIALS"
Expand Down Expand Up @@ -366,7 +368,7 @@
<service
android:name=".services.CallForegroundService"
android:exported="false"
android:foregroundServiceType="microphone|camera" />
android:foregroundServiceType="phoneCall|microphone|camera" />

<service android:name=".services.UnifiedPushService"
android:exported="false">
Expand Down
135 changes: 89 additions & 46 deletions app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import com.nextcloud.talk.call.MessageSenderMcu
import com.nextcloud.talk.call.MessageSenderNoMcu
import com.nextcloud.talk.call.MutableLocalCallParticipantModel
import com.nextcloud.talk.call.ReactionAnimator
import com.nextcloud.talk.call.TelecomManager
import com.nextcloud.talk.call.components.ParticipantGrid
import com.nextcloud.talk.call.components.SelfVideoView
import com.nextcloud.talk.call.components.screenshare.ScreenShareComponent
Expand Down Expand Up @@ -220,6 +221,9 @@ class CallActivity : CallBaseActivity() {
@Inject
var permissionUtil: PlatformPermissionUtil? = null

@Inject
lateinit var telecomManager: TelecomManager

@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
lateinit var callViewModel: CallViewModel
Expand Down Expand Up @@ -1602,6 +1606,7 @@ class CallActivity : CallBaseActivity() {
// The screen that started the call marked it as dialing, which hangup() would reset. Without resetting
// it here, chats would keep treating the app as being in a call.
ApplicationWideCurrentRoomHolder.getInstance().isDialing = false
telecomManager.endCurrentCall(roomToken)
}

super.onDestroy()
Expand Down Expand Up @@ -2218,6 +2223,7 @@ class CallActivity : CallBaseActivity() {

private fun hangup(shutDownView: Boolean, endCallForAll: Boolean) {
Log.d(TAG, "hangup! shutDownView=$shutDownView, endCallForAll=$endCallForAll")

joinRoomInitiated = false
if (shutDownView) {
setCallState(CallStatus.LEAVING)
Expand All @@ -2228,8 +2234,12 @@ class CallActivity : CallBaseActivity() {
dispose(nickSendingDisposable)
nickSendingDisposable = null

if (shutDownView) {
if (shutDownView || currentCallStatus == CallStatus.CALLING_TIMEOUT) {
terminateAudioVideo()
if (webSocketClient != null) {
webSocketClient!!.sendBye()
webSocketClient = null
}
}

val peerConnectionIdsToEnd: MutableList<String> = ArrayList(peerConnectionWrapperList.size)
Expand Down Expand Up @@ -2259,6 +2269,9 @@ class CallActivity : CallBaseActivity() {
}

hangupNetworkCalls(shutDownView, endCallForAll)
if (shutDownView) {
telecomManager.endCurrentCall(roomToken)
}
}

private fun terminateAudioVideo() {
Expand Down Expand Up @@ -2298,7 +2311,9 @@ class CallActivity : CallBaseActivity() {
}
localAudioTrack = null
localVideoTrack = null
if (TextUtils.isEmpty(credentials) && hasExternalSignalingServer) {
if (::conversationUser.isInitialized && conversationUser.id != null) {
WebSocketConnectionHelper.deleteExternalSignalingInstanceForUserEntity(conversationUser.id!!)
} else if (TextUtils.isEmpty(credentials) && hasExternalSignalingServer) {
WebSocketConnectionHelper.deleteExternalSignalingInstanceForUserEntity(-1)
}
}
Expand Down Expand Up @@ -2348,7 +2363,7 @@ class CallActivity : CallBaseActivity() {
startActivity(intent)
finish()
} else if (shutDownView) {
finish()
finishAndRemoveTask()
} else if (currentCallStatus === CallStatus.RECONNECTING ||
currentCallStatus === CallStatus.PUBLISHER_FAILED
) {
Expand All @@ -2357,52 +2372,55 @@ class CallActivity : CallBaseActivity() {
}

private fun openConversationListInPrimaryTask() {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
val appTasks = activityManager
?.appTasks
?.filter { appTask -> appTask.taskInfo?.baseActivity?.packageName == packageName }
.orEmpty()

val primaryTask = appTasks.firstOrNull { appTask ->
val taskInfo = appTask.taskInfo
val baseActivityName = taskInfo?.baseActivity?.className
taskInfo != null &&
taskInfo.taskId != taskId &&
baseActivityName == MainActivity::class.java.name
} ?: appTasks.firstOrNull { appTask ->
val taskInfo = appTask.taskInfo
val baseActivityName = taskInfo?.baseActivity?.className
taskInfo != null &&
taskInfo.taskId != taskId &&
baseActivityName != CallActivity::class.java.name &&
baseActivityName != CallNotificationActivity::class.java.name
}

if (primaryTask != null) {
val intent = Intent(context, ConversationsListActivity::class.java).apply {
putExtra(KEY_INTERNAL_USER_ID, conversationUser.id)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
primaryTask.startActivity(context, intent, null)
primaryTask.moveToFront()
val primaryTaskId = primaryTask.taskInfo?.taskId
appTasks
.filter { appTask ->
val taskInfo = appTask.taskInfo
val baseActivityName = taskInfo?.baseActivity?.className
val isCallTask = baseActivityName == CallActivity::class.java.name ||
baseActivityName == CallNotificationActivity::class.java.name
taskInfo != null && !isCallTask && taskInfo.taskId != primaryTaskId && taskInfo.taskId != taskId
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
val appTasks = activityManager
?.appTasks
?.filter { appTask -> appTask.taskInfo?.baseActivity?.packageName == packageName }
.orEmpty()

val primaryTask = appTasks.firstOrNull { appTask ->
val taskInfo = appTask.taskInfo
val baseActivityName = taskInfo?.baseActivity?.className
taskInfo != null &&
taskInfo.taskId != taskId &&
baseActivityName == MainActivity::class.java.name
} ?: appTasks.firstOrNull { appTask ->
val taskInfo = appTask.taskInfo
val baseActivityName = taskInfo?.baseActivity?.className
taskInfo != null &&
taskInfo.taskId != taskId &&
baseActivityName != CallActivity::class.java.name &&
baseActivityName != CallNotificationActivity::class.java.name
}

if (primaryTask != null) {
val intent = Intent(context, ConversationsListActivity::class.java).apply {
putExtra(KEY_INTERNAL_USER_ID, conversationUser.id)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
.forEach { it.finishAndRemoveTask() }
} else {
val mainIntent = Intent(context, MainActivity::class.java).apply {
action = Intent.ACTION_MAIN
addCategory(Intent.CATEGORY_LAUNCHER)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
primaryTask.startActivity(context, intent, null)
primaryTask.moveToFront()
val primaryTaskId = primaryTask.taskInfo?.taskId
appTasks
.filter { appTask ->
val taskInfo = appTask.taskInfo
val baseActivityName = taskInfo?.baseActivity?.className
val isCallTask = baseActivityName == CallActivity::class.java.name ||
baseActivityName == CallNotificationActivity::class.java.name
taskInfo != null && !isCallTask && taskInfo.taskId != primaryTaskId && taskInfo.taskId != taskId
}
.forEach { it.finishAndRemoveTask() }
return
}
startActivity(mainIntent)
}

val mainIntent = Intent(context, MainActivity::class.java).apply {
action = Intent.ACTION_MAIN
addCategory(Intent.CATEGORY_LAUNCHER)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
}
startActivity(mainIntent)
}

private fun startVideoCapture(isPortrait: Boolean) {
Expand Down Expand Up @@ -2947,7 +2965,31 @@ class CallActivity : CallBaseActivity() {
}
}

private fun activateTelecomCall() {
val disconnectHandler: () -> Unit = {
runOnUiThread {
if (!isFinishing && !isDestroyed && currentCallStatus != CallStatus.LEAVING) {
hangup(shutDownView = true, endCallForAll = false)
}
}
}

if (!telecomManager.hasActiveCall(roomToken)) {
telecomManager.addOutgoingCall(
displayName = conversationName.takeIf {
!it.isNullOrBlank()
} ?: getString(R.string.nc_app_product_name),
roomToken = roomToken ?: "",
isVideo = !isVoiceOnlyCall,
onDisconnectCall = disconnectHandler
)
} else {
telecomManager.setCallActive(roomToken, onDisconnectCall = disconnectHandler)
}
}

private fun handleCallStateInConversation() {
activateTelecomCall()
stopCallingSound()
if (binding!!.callStates.callStateRelativeLayout.visibility != View.INVISIBLE) {
binding!!.callStates.callStateRelativeLayout.visibility = View.INVISIBLE
Expand All @@ -2964,6 +3006,7 @@ class CallActivity : CallBaseActivity() {
}

private fun handleCallStateJoined() {
activateTelecomCall()
if (isIncomingCallFromNotification) {
binding!!.callStates.callStateTextView.setText(R.string.nc_call_incoming)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import com.nextcloud.talk.errorhandling.ExceptionHandler
import com.nextcloud.talk.logger.LoggerImpl
import com.nextcloud.talk.account.BrowserLoginActivity
import com.nextcloud.talk.dagger.modules.ApplicationScope
import com.nextcloud.talk.call.TelecomManager
import com.nextcloud.talk.dagger.modules.BusModule
import com.nextcloud.talk.dagger.modules.ContextModule
import com.nextcloud.talk.dagger.modules.DaosModule
Expand Down Expand Up @@ -124,6 +125,9 @@ class NextcloudTalkApplication :
lateinit var logger: LoggerImpl
//endregion

@Inject
lateinit var telecomManager: TelecomManager

//region private methods
private fun installExceptionHandler() {
val defaultHandler = Thread.getDefaultUncaughtExceptionHandler()
Expand Down Expand Up @@ -215,11 +219,13 @@ class NextcloudTalkApplication :
securityKeyManager.init(this, securityKeyConfigBuilder.build())
initializeWebRtc()
buildComponent()

componentApplication.inject(this)

telecomManager.registerAppWithTelecom()
Comment thread
thecyberd3m0n marked this conversation as resolved.
DavUtils.registerCustomFactories()

Security.insertProviderAt(Conscrypt.newProvider(), 1)

componentApplication.inject(this)
installExceptionHandler()

ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {
Expand Down
Loading