mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-26 08:18:07 +00:00
Compare commits
9 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12fb814fb8 | ||
|
|
d7418073d6 | ||
|
|
9b934f8f15 | ||
|
|
2d220dd01a | ||
|
|
fb7d2d846a | ||
|
|
d0797fb54c | ||
|
|
124371f406 | ||
|
|
6af3a99470 | ||
|
|
8674a2b712 |
12 changed files with 94 additions and 35 deletions
|
|
@ -12,6 +12,15 @@ Group changes to describe their impact on the project, as follows:
|
||||||
|
|
||||||
## [4.7.0] - Unreleased
|
## [4.7.0] - Unreleased
|
||||||
|
|
||||||
|
## [4.6.1] - 2022-02-14
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Quit button not working when background mode was enabled
|
||||||
|
- Crash when background mode was enabled and service notification channel was disabled
|
||||||
|
- Crashes while changing audio route
|
||||||
|
- Crash while fetching contacts
|
||||||
|
- Crash when rotating the device (SDK fix)
|
||||||
|
|
||||||
## [4.6.0] - 2022-02-09
|
## [4.6.0] - 2022-02-09
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ plugins {
|
||||||
id 'org.jlleitschuh.gradle.ktlint'
|
id 'org.jlleitschuh.gradle.ktlint'
|
||||||
}
|
}
|
||||||
|
|
||||||
def appVersionName = "4.6.0"
|
def appVersionName = "4.6.1"
|
||||||
def appVersionCode = 40600 // 4.06.00
|
def appVersionCode = 40601 // 4.06.01
|
||||||
|
|
||||||
static def getPackageName() {
|
static def getPackageName() {
|
||||||
return "org.linphone"
|
return "org.linphone"
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import android.view.View
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import org.linphone.LinphoneApplication
|
import org.linphone.LinphoneApplication
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
import org.linphone.activities.assistant.AssistantActivity
|
import org.linphone.activities.SnackBarActivity
|
||||||
import org.linphone.activities.assistant.viewmodels.*
|
import org.linphone.activities.assistant.viewmodels.*
|
||||||
import org.linphone.activities.navigateToEchoCancellerCalibration
|
import org.linphone.activities.navigateToEchoCancellerCalibration
|
||||||
import org.linphone.activities.navigateToPhoneAccountValidation
|
import org.linphone.activities.navigateToPhoneAccountValidation
|
||||||
|
|
@ -99,7 +99,7 @@ class PhoneAccountLinkingFragment : AbstractPhoneFragment<AssistantPhoneAccountL
|
||||||
viewLifecycleOwner
|
viewLifecycleOwner
|
||||||
) {
|
) {
|
||||||
it.consume { message ->
|
it.consume { message ->
|
||||||
(requireActivity() as AssistantActivity).showSnackBar(message)
|
(requireActivity() as SnackBarActivity).showSnackBar(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -329,6 +329,11 @@ class MainActivity : GenericActivity(), SnackBarActivity, NavController.OnDestin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prevent this intent to be processed again
|
||||||
|
intent.action = null
|
||||||
|
intent.data = null
|
||||||
|
intent.extras?.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleTelOrSipUri(uri: Uri) {
|
private fun handleTelOrSipUri(uri: Uri) {
|
||||||
|
|
|
||||||
|
|
@ -308,6 +308,16 @@ class DetailChatRoomFragment : MasterFragment<ChatRoomDetailFragmentBinding, Cha
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chatSendingViewModel.messageSentEvent.observe(
|
||||||
|
viewLifecycleOwner
|
||||||
|
) {
|
||||||
|
it.consume {
|
||||||
|
Log.i("[Chat Room] Message sent")
|
||||||
|
// Reset this to ensure sent message will be visible
|
||||||
|
viewModel.isUserScrollingUp.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
listViewModel.events.observe(
|
listViewModel.events.observe(
|
||||||
viewLifecycleOwner
|
viewLifecycleOwner
|
||||||
) { events ->
|
) { events ->
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,10 @@ class ChatMessageSendingViewModel(private val chatRoom: ChatRoom) : ViewModel()
|
||||||
MutableLiveData<Event<Boolean>>()
|
MutableLiveData<Event<Boolean>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val messageSentEvent: MutableLiveData<Event<Boolean>> by lazy {
|
||||||
|
MutableLiveData<Event<Boolean>>()
|
||||||
|
}
|
||||||
|
|
||||||
val voiceRecordingProgressBarMax = 10000
|
val voiceRecordingProgressBarMax = 10000
|
||||||
|
|
||||||
val isPendingVoiceRecord = MutableLiveData<Boolean>()
|
val isPendingVoiceRecord = MutableLiveData<Boolean>()
|
||||||
|
|
@ -261,6 +265,8 @@ class ChatMessageSendingViewModel(private val chatRoom: ChatRoom) : ViewModel()
|
||||||
attachments.value.orEmpty().forEach(ChatMessageAttachmentData::destroy)
|
attachments.value.orEmpty().forEach(ChatMessageAttachmentData::destroy)
|
||||||
attachments.value = arrayListOf()
|
attachments.value = arrayListOf()
|
||||||
textToSend.value = ""
|
textToSend.value = ""
|
||||||
|
|
||||||
|
messageSentEvent.value = Event(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun transferMessage(chatMessage: ChatMessage) {
|
fun transferMessage(chatMessage: ChatMessage) {
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ import androidx.lifecycle.lifecycleScope
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
import org.linphone.activities.GenericFragment
|
import org.linphone.activities.GenericFragment
|
||||||
import org.linphone.activities.assistant.AssistantActivity
|
import org.linphone.activities.assistant.AssistantActivity
|
||||||
|
|
@ -113,12 +112,9 @@ class SideMenuFragment : GenericFragment<SideMenuFragmentBinding>() {
|
||||||
Log.i("[Side Menu] Quitting app")
|
Log.i("[Side Menu] Quitting app")
|
||||||
requireActivity().finishAndRemoveTask()
|
requireActivity().finishAndRemoveTask()
|
||||||
|
|
||||||
if (!corePreferences.keepServiceAlive) {
|
Log.i("[Side Menu] Stopping Core Context")
|
||||||
Log.i("[Side Menu] Stopping Core")
|
coreContext.notificationsManager.stopForegroundNotification()
|
||||||
coreContext.stop()
|
coreContext.stop()
|
||||||
} else {
|
|
||||||
Log.w("[Side Menu] Keep Service alive setting enabled, don't destroy the Core")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onBackPressedCallback.isEnabled = false
|
onBackPressedCallback.isEnabled = false
|
||||||
|
|
|
||||||
|
|
@ -259,10 +259,16 @@ class Api26Compatibility {
|
||||||
|
|
||||||
fun changeAudioRouteForTelecomManager(connection: NativeCallWrapper, route: Int): Boolean {
|
fun changeAudioRouteForTelecomManager(connection: NativeCallWrapper, route: Int): Boolean {
|
||||||
Log.i("[Telecom Helper] Changing audio route [$route] on connection ${connection.callId}")
|
Log.i("[Telecom Helper] Changing audio route [$route] on connection ${connection.callId}")
|
||||||
if (connection.callAudioState.route == route) {
|
|
||||||
|
val audioState = connection.callAudioState
|
||||||
|
if (audioState != null && audioState.route == route) {
|
||||||
Log.w("[Telecom Helper] Connection is already using this route")
|
Log.w("[Telecom Helper] Connection is already using this route")
|
||||||
return false
|
return false
|
||||||
|
} else if (audioState == null) {
|
||||||
|
Log.w("[Telecom Helper] Failed to retrieve connection's call audio state!")
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
connection.setAudioRoute(route)
|
connection.setAudioRoute(route)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -109,14 +109,20 @@ class AsyncContactsLoader(private val context: Context) :
|
||||||
Log.i("[Contacts Loader] Only fetching contacts in default directory")
|
Log.i("[Contacts Loader] Only fetching contacts in default directory")
|
||||||
selection = ContactsContract.Data.IN_DEFAULT_DIRECTORY + " == 1"
|
selection = ContactsContract.Data.IN_DEFAULT_DIRECTORY + " == 1"
|
||||||
}
|
}
|
||||||
val cursor: Cursor? = context.contentResolver
|
|
||||||
.query(
|
val cursor: Cursor? = try {
|
||||||
ContactsContract.Data.CONTENT_URI,
|
context.contentResolver
|
||||||
projection,
|
.query(
|
||||||
selection,
|
ContactsContract.Data.CONTENT_URI,
|
||||||
null,
|
projection,
|
||||||
null
|
selection,
|
||||||
)
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("[Contacts Loader] Failed to get contacts cursor: $e")
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
Log.i("[Contacts Loader] Found ${cursor.count} entries in cursor")
|
Log.i("[Contacts Loader] Found ${cursor.count} entries in cursor")
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,11 @@ package org.linphone.core
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||||
|
import org.linphone.R
|
||||||
|
import org.linphone.compatibility.Compatibility
|
||||||
import org.linphone.core.tools.Log
|
import org.linphone.core.tools.Log
|
||||||
|
|
||||||
class BootReceiver : BroadcastReceiver() {
|
class BootReceiver : BroadcastReceiver() {
|
||||||
|
|
@ -32,18 +35,27 @@ class BootReceiver : BroadcastReceiver() {
|
||||||
val autoStart = corePreferences.autoStart
|
val autoStart = corePreferences.autoStart
|
||||||
Log.i("[Boot Receiver] Device is starting, autoStart is $autoStart")
|
Log.i("[Boot Receiver] Device is starting, autoStart is $autoStart")
|
||||||
if (autoStart) {
|
if (autoStart) {
|
||||||
val serviceIntent = Intent(Intent.ACTION_MAIN).setClass(context, CoreService::class.java)
|
startService(context)
|
||||||
serviceIntent.putExtra("StartForeground", true)
|
|
||||||
ContextCompat.startForegroundService(context, serviceIntent)
|
|
||||||
}
|
}
|
||||||
} else if (intent.action.equals(Intent.ACTION_MY_PACKAGE_REPLACED, ignoreCase = true)) {
|
} else if (intent.action.equals(Intent.ACTION_MY_PACKAGE_REPLACED, ignoreCase = true)) {
|
||||||
val autoStart = corePreferences.autoStart
|
val autoStart = corePreferences.autoStart
|
||||||
Log.i("[Boot Receiver] App has been updated, autoStart is $autoStart")
|
Log.i("[Boot Receiver] App has been updated, autoStart is $autoStart")
|
||||||
if (autoStart) {
|
if (autoStart) {
|
||||||
val serviceIntent = Intent(Intent.ACTION_MAIN).setClass(context, CoreService::class.java)
|
startService(context)
|
||||||
serviceIntent.putExtra("StartForeground", true)
|
|
||||||
ContextCompat.startForegroundService(context, serviceIntent)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun startService(context: Context) {
|
||||||
|
val serviceChannel = context.getString(R.string.notification_channel_service_id)
|
||||||
|
val notificationManager = NotificationManagerCompat.from(context)
|
||||||
|
if (Compatibility.getChannelImportance(notificationManager, serviceChannel) == NotificationManagerCompat.IMPORTANCE_NONE) {
|
||||||
|
Log.w("[Boot Receiver] Service channel is disabled!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val serviceIntent = Intent(Intent.ACTION_MAIN).setClass(context, CoreService::class.java)
|
||||||
|
serviceIntent.putExtra("StartForeground", true)
|
||||||
|
ContextCompat.startForegroundService(context, serviceIntent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -281,6 +281,12 @@ class NotificationsManager(private val context: Context) {
|
||||||
/* Service related */
|
/* Service related */
|
||||||
|
|
||||||
fun startForeground() {
|
fun startForeground() {
|
||||||
|
val serviceChannel = context.getString(R.string.notification_channel_service_id)
|
||||||
|
if (Compatibility.getChannelImportance(notificationManager, serviceChannel) == NotificationManagerCompat.IMPORTANCE_NONE) {
|
||||||
|
Log.w("[Notifications Manager] Service channel is disabled!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val coreService = service
|
val coreService = service
|
||||||
if (coreService != null) {
|
if (coreService != null) {
|
||||||
startForeground(coreService, useAutoStartDescription = false)
|
startForeground(coreService, useAutoStartDescription = false)
|
||||||
|
|
@ -327,6 +333,10 @@ class NotificationsManager(private val context: Context) {
|
||||||
fun startForeground(coreService: CoreService, useAutoStartDescription: Boolean = true) {
|
fun startForeground(coreService: CoreService, useAutoStartDescription: Boolean = true) {
|
||||||
if (serviceNotification == null) {
|
if (serviceNotification == null) {
|
||||||
createServiceNotification(useAutoStartDescription)
|
createServiceNotification(useAutoStartDescription)
|
||||||
|
if (serviceNotification == null) {
|
||||||
|
Log.e("[Notifications Manager] Failed to create service notification, aborting foreground service!")
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
currentForegroundServiceNotificationId = SERVICE_NOTIF_ID
|
currentForegroundServiceNotificationId = SERVICE_NOTIF_ID
|
||||||
Log.i("[Notifications Manager] Starting service as foreground [$currentForegroundServiceNotificationId]")
|
Log.i("[Notifications Manager] Starting service as foreground [$currentForegroundServiceNotificationId]")
|
||||||
|
|
@ -342,7 +352,7 @@ class NotificationsManager(private val context: Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun stopForegroundNotification() {
|
fun stopForegroundNotification() {
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
Log.i("[Notifications Manager] Stopping service as foreground [$currentForegroundServiceNotificationId]")
|
Log.i("[Notifications Manager] Stopping service as foreground [$currentForegroundServiceNotificationId]")
|
||||||
service?.stopForeground(true)
|
service?.stopForeground(true)
|
||||||
|
|
|
||||||
|
|
@ -96,11 +96,10 @@ class AudioRouteUtils {
|
||||||
types: List<AudioDevice.Type>,
|
types: List<AudioDevice.Type>,
|
||||||
skipTelecom: Boolean = false
|
skipTelecom: Boolean = false
|
||||||
) {
|
) {
|
||||||
val currentCall = call ?: coreContext.core.currentCall ?: coreContext.core.calls[0]
|
val currentCall = call ?: coreContext.core.currentCall ?: coreContext.core.calls.firstOrNull()
|
||||||
if ((call != null || currentCall != null) && !skipTelecom && TelecomHelper.exists()) {
|
if (currentCall != null && !skipTelecom && TelecomHelper.exists()) {
|
||||||
val callToUse = call ?: currentCall
|
|
||||||
Log.i("[Audio Route Helper] Call provided & Telecom Helper exists, trying to dispatch audio route change through Telecom API")
|
Log.i("[Audio Route Helper] Call provided & Telecom Helper exists, trying to dispatch audio route change through Telecom API")
|
||||||
val connection = TelecomHelper.get().findConnectionForCallId(callToUse.callLog.callId)
|
val connection = TelecomHelper.get().findConnectionForCallId(currentCall.callLog.callId)
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
val route = when (types.first()) {
|
val route = when (types.first()) {
|
||||||
AudioDevice.Type.Earpiece -> CallAudioState.ROUTE_EARPIECE
|
AudioDevice.Type.Earpiece -> CallAudioState.ROUTE_EARPIECE
|
||||||
|
|
@ -114,13 +113,13 @@ class AudioRouteUtils {
|
||||||
// but this time with skipTelecom = true
|
// but this time with skipTelecom = true
|
||||||
if (!Compatibility.changeAudioRouteForTelecomManager(connection, route)) {
|
if (!Compatibility.changeAudioRouteForTelecomManager(connection, route)) {
|
||||||
Log.w("[Audio Route Helper] Connection is already using this route internally, make the change!")
|
Log.w("[Audio Route Helper] Connection is already using this route internally, make the change!")
|
||||||
applyAudioRouteChange(callToUse, types)
|
applyAudioRouteChange(currentCall, types)
|
||||||
changeCaptureDeviceToMatchAudioRoute(callToUse, types)
|
changeCaptureDeviceToMatchAudioRoute(currentCall, types)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.w("[Audio Route Helper] Telecom Helper found but no matching connection!")
|
Log.w("[Audio Route Helper] Telecom Helper found but no matching connection!")
|
||||||
applyAudioRouteChange(callToUse, types)
|
applyAudioRouteChange(currentCall, types)
|
||||||
changeCaptureDeviceToMatchAudioRoute(callToUse, types)
|
changeCaptureDeviceToMatchAudioRoute(currentCall, types)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
applyAudioRouteChange(call, types)
|
applyAudioRouteChange(call, types)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue