mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-04-26 16:48:35 +00:00
Added data sync keep alive service for third party accounts without push notifications
This commit is contained in:
parent
7f1dc95cfc
commit
486f905d65
12 changed files with 279 additions and 13 deletions
|
|
@ -163,6 +163,13 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".core.CoreKeepAliveThirdPartyAccountsService"
|
||||||
|
android:exported="false"
|
||||||
|
android:foregroundServiceType="dataSync"
|
||||||
|
android:stopWithTask="false"
|
||||||
|
android:label="@string/app_name" />
|
||||||
|
|
||||||
<!-- Receivers -->
|
<!-- Receivers -->
|
||||||
|
|
||||||
<receiver android:name=".core.CorePushReceiver"
|
<receiver android:name=".core.CorePushReceiver"
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ import android.app.Activity
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.app.PictureInPictureParams
|
import android.app.PictureInPictureParams
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import org.linphone.core.tools.Log
|
import org.linphone.core.tools.Log
|
||||||
|
|
@ -43,6 +45,10 @@ class Api28Compatibility {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startForegroundService(context: Context, intent: Intent) {
|
||||||
|
context.startForegroundService(intent)
|
||||||
|
}
|
||||||
|
|
||||||
fun enterPipMode(activity: Activity): Boolean {
|
fun enterPipMode(activity: Activity): Boolean {
|
||||||
val params = PictureInPictureParams.Builder()
|
val params = PictureInPictureParams.Builder()
|
||||||
.setAspectRatio(AppUtils.getPipRatio(activity))
|
.setAspectRatio(AppUtils.getPipRatio(activity))
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,11 @@
|
||||||
package org.linphone.compatibility
|
package org.linphone.compatibility
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.app.ForegroundServiceStartNotAllowedException
|
||||||
import android.app.PictureInPictureParams
|
import android.app.PictureInPictureParams
|
||||||
import android.app.UiModeManager
|
import android.app.UiModeManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.graphics.RenderEffect
|
import android.graphics.RenderEffect
|
||||||
import android.graphics.Shader
|
import android.graphics.Shader
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
|
@ -78,5 +80,17 @@ class Api31Compatibility {
|
||||||
}
|
}
|
||||||
uiManager?.setApplicationNightMode(UiModeManager.MODE_NIGHT_AUTO)
|
uiManager?.setApplicationNightMode(UiModeManager.MODE_NIGHT_AUTO)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startForegroundService(context: Context, intent: Intent) {
|
||||||
|
try {
|
||||||
|
context.startForegroundService(intent)
|
||||||
|
} catch (fssnae: ForegroundServiceStartNotAllowedException) {
|
||||||
|
Log.e("$TAG Can't start service as foreground! $fssnae")
|
||||||
|
} catch (se: SecurityException) {
|
||||||
|
Log.e("$TAG Can't start service as foreground! $se")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e("$TAG Can't start service as foreground! $e")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ class Compatibility {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "[Compatibility]"
|
private const val TAG = "[Compatibility]"
|
||||||
|
|
||||||
|
const val FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1 // Matches ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
|
||||||
const val FOREGROUND_SERVICE_TYPE_PHONE_CALL = 4 // Matches ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL
|
const val FOREGROUND_SERVICE_TYPE_PHONE_CALL = 4 // Matches ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL
|
||||||
const val FOREGROUND_SERVICE_TYPE_CAMERA = 64 // Matches ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
|
const val FOREGROUND_SERVICE_TYPE_CAMERA = 64 // Matches ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
|
||||||
const val FOREGROUND_SERVICE_TYPE_MICROPHONE = 128 // ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE
|
const val FOREGROUND_SERVICE_TYPE_MICROPHONE = 128 // ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE
|
||||||
|
|
@ -59,6 +60,14 @@ class Compatibility {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startForegroundService(context: Context, intent: Intent) {
|
||||||
|
if (Version.sdkAboveOrEqual(Version.API31_ANDROID_12)) {
|
||||||
|
Api31Compatibility.startForegroundService(context, intent)
|
||||||
|
} else {
|
||||||
|
Api28Compatibility.startForegroundService(context, intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun setBlurRenderEffect(view: View) {
|
fun setBlurRenderEffect(view: View) {
|
||||||
if (Version.sdkAboveOrEqual(Version.API31_ANDROID_12)) {
|
if (Version.sdkAboveOrEqual(Version.API31_ANDROID_12)) {
|
||||||
Api31Compatibility.setBlurRenderEffect(view)
|
Api31Compatibility.setBlurRenderEffect(view)
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import androidx.lifecycle.MutableLiveData
|
||||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
import org.linphone.BuildConfig
|
import org.linphone.BuildConfig
|
||||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||||
|
import org.linphone.compatibility.Compatibility
|
||||||
import org.linphone.contacts.ContactsManager
|
import org.linphone.contacts.ContactsManager
|
||||||
import org.linphone.core.tools.Log
|
import org.linphone.core.tools.Log
|
||||||
import org.linphone.notifications.NotificationsManager
|
import org.linphone.notifications.NotificationsManager
|
||||||
|
|
@ -279,6 +280,10 @@ class CoreContext @UiThread constructor(val context: Context) : HandlerThread("C
|
||||||
corePreferences.linphoneConfigurationVersion = CorePreferences.CURRENT_VERSION
|
corePreferences.linphoneConfigurationVersion = CorePreferences.CURRENT_VERSION
|
||||||
|
|
||||||
Log.i("$TAG Report Core created and started")
|
Log.i("$TAG Report Core created and started")
|
||||||
|
|
||||||
|
if (corePreferences.keepServiceAlive) {
|
||||||
|
startKeepAliveService()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
|
|
@ -529,6 +534,30 @@ class CoreContext @UiThread constructor(val context: Context) : HandlerThread("C
|
||||||
context.startActivity(intent)
|
context.startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
fun startKeepAliveService() {
|
||||||
|
val serviceIntent = Intent(Intent.ACTION_MAIN).setClass(
|
||||||
|
context,
|
||||||
|
CoreKeepAliveThirdPartyAccountsService::class.java
|
||||||
|
)
|
||||||
|
Log.i(
|
||||||
|
"$TAG Starting Keep alive for third party accounts Service (as foreground)"
|
||||||
|
)
|
||||||
|
Compatibility.startForegroundService(context, serviceIntent)
|
||||||
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
fun stopKeepAliveService() {
|
||||||
|
val serviceIntent = Intent(Intent.ACTION_MAIN).setClass(
|
||||||
|
context,
|
||||||
|
CoreKeepAliveThirdPartyAccountsService::class.java
|
||||||
|
)
|
||||||
|
Log.i(
|
||||||
|
"$TAG Stopping Keep alive for third party accounts Service"
|
||||||
|
)
|
||||||
|
context.stopService(serviceIntent)
|
||||||
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
fun updateFriendListsSubscriptionDependingOnDefaultAccount() {
|
fun updateFriendListsSubscriptionDependingOnDefaultAccount() {
|
||||||
val account = core.defaultAccount
|
val account = core.defaultAccount
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2023 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-android
|
||||||
|
* (see https://www.linphone.org).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package org.linphone.core
|
||||||
|
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.IBinder
|
||||||
|
import androidx.annotation.MainThread
|
||||||
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
|
import org.linphone.core.tools.Log
|
||||||
|
|
||||||
|
@MainThread
|
||||||
|
class CoreKeepAliveThirdPartyAccountsService : Service() {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "[Core Keep Alive Third Party Accounts Service]"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
Log.i("$TAG Created")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
Log.i("$TAG onStartCommand")
|
||||||
|
coreContext.notificationsManager.onKeepAliveServiceStarted(this)
|
||||||
|
return super.onStartCommand(intent, flags, startId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTaskRemoved(rootIntent: Intent?) {
|
||||||
|
Log.i("$TAG Task removed, doing nothing")
|
||||||
|
super.onTaskRemoved(rootIntent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
Log.i("$TAG onDestroy")
|
||||||
|
coreContext.notificationsManager.onKeepAliveServiceDestroyed()
|
||||||
|
super.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBind(p0: Intent?): IBinder? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -71,6 +71,13 @@ class CorePreferences @UiThread constructor(private val context: Context) {
|
||||||
config.setBool("app", "publish_presence", value)
|
config.setBool("app", "publish_presence", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@get:WorkerThread @set:WorkerThread
|
||||||
|
var keepServiceAlive: Boolean
|
||||||
|
get() = config.getBool("app", "keep_service_alive", false)
|
||||||
|
set(value) {
|
||||||
|
config.setBool("app", "keep_service_alive", value)
|
||||||
|
}
|
||||||
|
|
||||||
// Calls settings
|
// Calls settings
|
||||||
|
|
||||||
@get:WorkerThread @set:WorkerThread
|
@get:WorkerThread @set:WorkerThread
|
||||||
|
|
@ -104,6 +111,7 @@ class CorePreferences @UiThread constructor(private val context: Context) {
|
||||||
|
|
||||||
// Conversation settings
|
// Conversation settings
|
||||||
|
|
||||||
|
@get:WorkerThread @set:WorkerThread
|
||||||
var exportMediaToNativeGallery: Boolean // TODO: use it!
|
var exportMediaToNativeGallery: Boolean // TODO: use it!
|
||||||
// Keep old name for backward compatibility
|
// Keep old name for backward compatibility
|
||||||
get() = config.getBool("app", "make_downloaded_images_public_in_gallery", true)
|
get() = config.getBool("app", "make_downloaded_images_public_in_gallery", true)
|
||||||
|
|
@ -113,6 +121,7 @@ class CorePreferences @UiThread constructor(private val context: Context) {
|
||||||
|
|
||||||
/* Voice Recordings */
|
/* Voice Recordings */
|
||||||
|
|
||||||
|
@get:WorkerThread @set:WorkerThread
|
||||||
var voiceRecordingMaxDuration: Int
|
var voiceRecordingMaxDuration: Int
|
||||||
get() = config.getInt("app", "voice_recording_max_duration", 600000) // in ms
|
get() = config.getInt("app", "voice_recording_max_duration", 600000) // in ms
|
||||||
set(value) = config.setInt("app", "voice_recording_max_duration", value)
|
set(value) = config.setInt("app", "voice_recording_max_duration", value)
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ import org.linphone.core.ChatMessageReaction
|
||||||
import org.linphone.core.ChatRoom
|
import org.linphone.core.ChatRoom
|
||||||
import org.linphone.core.Core
|
import org.linphone.core.Core
|
||||||
import org.linphone.core.CoreForegroundService
|
import org.linphone.core.CoreForegroundService
|
||||||
|
import org.linphone.core.CoreKeepAliveThirdPartyAccountsService
|
||||||
import org.linphone.core.CoreListenerStub
|
import org.linphone.core.CoreListenerStub
|
||||||
import org.linphone.core.CorePreferences
|
import org.linphone.core.CorePreferences
|
||||||
import org.linphone.core.Friend
|
import org.linphone.core.Friend
|
||||||
|
|
@ -93,10 +94,12 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
||||||
const val CHAT_NOTIFICATIONS_GROUP = "CHAT_NOTIF_GROUP"
|
const val CHAT_NOTIFICATIONS_GROUP = "CHAT_NOTIF_GROUP"
|
||||||
|
|
||||||
private const val INCOMING_CALL_ID = 1
|
private const val INCOMING_CALL_ID = 1
|
||||||
|
private const val KEEP_ALIVE_FOR_THIRD_PARTY_ACCOUNTS_ID = 5
|
||||||
private const val MISSED_CALL_ID = 10
|
private const val MISSED_CALL_ID = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
private var currentForegroundServiceNotificationId = -1
|
private var currentForegroundServiceNotificationId = -1
|
||||||
|
private var currentKeepAliveThirdPartyAccountsForegroundServiceNotificationId = -1
|
||||||
|
|
||||||
private var currentlyRingingCallRemoteAddress: Address? = null
|
private var currentlyRingingCallRemoteAddress: Address? = null
|
||||||
|
|
||||||
|
|
@ -137,7 +140,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
||||||
val notifiable = getNotifiableForCall(call)
|
val notifiable = getNotifiableForCall(call)
|
||||||
if (notifiable.notificationId == currentForegroundServiceNotificationId) {
|
if (notifiable.notificationId == currentForegroundServiceNotificationId) {
|
||||||
Log.i(
|
Log.i(
|
||||||
"$TAG Update foreground service type in case video was enabled/disabled since last time"
|
"$TAG Update foreground Service type in case video was enabled/disabled since last time"
|
||||||
)
|
)
|
||||||
startCallForeground(call)
|
startCallForeground(call)
|
||||||
}
|
}
|
||||||
|
|
@ -349,6 +352,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var coreService: CoreForegroundService? = null
|
private var coreService: CoreForegroundService? = null
|
||||||
|
private var keepAliveService: CoreKeepAliveThirdPartyAccountsService? = null
|
||||||
|
|
||||||
private val callNotificationsMap: HashMap<String, Notifiable> = HashMap()
|
private val callNotificationsMap: HashMap<String, Notifiable> = HashMap()
|
||||||
private val chatNotificationsMap: HashMap<String, Notifiable> = HashMap()
|
private val chatNotificationsMap: HashMap<String, Notifiable> = HashMap()
|
||||||
|
|
@ -397,7 +401,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
||||||
stopCallForeground()
|
stopCallForeground()
|
||||||
} else if (currentForegroundServiceNotificationId == -1) {
|
} else if (currentForegroundServiceNotificationId == -1) {
|
||||||
Log.i(
|
Log.i(
|
||||||
"$TAG At least a call is still running and no foreground service notification was found"
|
"$TAG At least a call is still running and no foreground Service notification was found"
|
||||||
)
|
)
|
||||||
val call = core.currentCall ?: core.calls.first()
|
val call = core.currentCall ?: core.calls.first()
|
||||||
startCallForeground(call)
|
startCallForeground(call)
|
||||||
|
|
@ -411,6 +415,20 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
||||||
coreService = null
|
coreService = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MainThread
|
||||||
|
fun onKeepAliveServiceStarted(service: CoreKeepAliveThirdPartyAccountsService) {
|
||||||
|
Log.i("$TAG Keep app alive for third party accounts Service has been started")
|
||||||
|
keepAliveService = service
|
||||||
|
startKeepAliveServiceForeground()
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainThread
|
||||||
|
fun onKeepAliveServiceDestroyed() {
|
||||||
|
Log.i("$TAG Keep app alive for third party accounts Service has been destroyed")
|
||||||
|
stopKeepAliveServiceForeground()
|
||||||
|
keepAliveService = null
|
||||||
|
}
|
||||||
|
|
||||||
@MainThread
|
@MainThread
|
||||||
private fun createChannels(clearPreviousChannels: Boolean) {
|
private fun createChannels(clearPreviousChannels: Boolean) {
|
||||||
if (clearPreviousChannels) {
|
if (clearPreviousChannels) {
|
||||||
|
|
@ -421,7 +439,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createServiceChannel()
|
createThirdPartyAccountKeepAliveServiceChannel()
|
||||||
createIncomingCallNotificationChannel()
|
createIncomingCallNotificationChannel()
|
||||||
createMissedCallNotificationChannel()
|
createMissedCallNotificationChannel()
|
||||||
createActiveCallNotificationChannel()
|
createActiveCallNotificationChannel()
|
||||||
|
|
@ -608,7 +626,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
||||||
) {
|
) {
|
||||||
mask = mask or Compatibility.FOREGROUND_SERVICE_TYPE_MICROPHONE
|
mask = mask or Compatibility.FOREGROUND_SERVICE_TYPE_MICROPHONE
|
||||||
Log.i(
|
Log.i(
|
||||||
"$TAG RECORD_AUDIO permission has been granted, adding FOREGROUND_SERVICE_TYPE_MICROPHONE to foreground service types mask"
|
"$TAG RECORD_AUDIO permission has been granted, adding FOREGROUND_SERVICE_TYPE_MICROPHONE to foreground Service types mask"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val isSendingVideo = when (call.currentParams.videoDirection) {
|
val isSendingVideo = when (call.currentParams.videoDirection) {
|
||||||
|
|
@ -623,7 +641,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
||||||
) {
|
) {
|
||||||
mask = mask or Compatibility.FOREGROUND_SERVICE_TYPE_CAMERA
|
mask = mask or Compatibility.FOREGROUND_SERVICE_TYPE_CAMERA
|
||||||
Log.i(
|
Log.i(
|
||||||
"$TAG CAMERA permission has been granted, adding FOREGROUND_SERVICE_TYPE_CAMERA to foreground service types mask"
|
"$TAG CAMERA permission has been granted, adding FOREGROUND_SERVICE_TYPE_CAMERA to foreground Service types mask"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -651,13 +669,13 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
||||||
val service = coreService
|
val service = coreService
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
Log.i(
|
Log.i(
|
||||||
"$TAG Stopping foreground service (was using notification ID [$currentForegroundServiceNotificationId])"
|
"$TAG Stopping foreground Service (was using notification ID [$currentForegroundServiceNotificationId])"
|
||||||
)
|
)
|
||||||
service.stopForeground(STOP_FOREGROUND_REMOVE)
|
service.stopForeground(STOP_FOREGROUND_REMOVE)
|
||||||
service.stopSelf()
|
service.stopSelf()
|
||||||
currentForegroundServiceNotificationId = -1
|
currentForegroundServiceNotificationId = -1
|
||||||
} else {
|
} else {
|
||||||
Log.w("$TAG Can't stop foreground service & notif, no service was found")
|
Log.w("$TAG Can't stop foreground Service & notif, no Service was found")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -806,7 +824,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
||||||
if (coreService == null && tag == null) {
|
if (coreService == null && tag == null) {
|
||||||
// We can't notify using CallStyle if there isn't a foreground service running
|
// We can't notify using CallStyle if there isn't a foreground service running
|
||||||
Log.w(
|
Log.w(
|
||||||
"$TAG Foreground service hasn't started yet, can't display a CallStyle notification until then: $iae"
|
"$TAG Foreground Service hasn't started yet, can't display a CallStyle notification until then: $iae"
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Log.e("$TAG Illegal Argument Exception occurred: $iae")
|
Log.e("$TAG Illegal Argument Exception occurred: $iae")
|
||||||
|
|
@ -1245,6 +1263,66 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MainThread
|
||||||
|
private fun startKeepAliveServiceForeground() {
|
||||||
|
Log.i(
|
||||||
|
"$TAG Trying to start keep alive for third party accounts foreground Service using call notification"
|
||||||
|
)
|
||||||
|
|
||||||
|
val channelId = context.getString(R.string.notification_channel_service_id)
|
||||||
|
val channel = notificationManager.getNotificationChannel(channelId)
|
||||||
|
val importance = channel?.importance ?: NotificationManagerCompat.IMPORTANCE_NONE
|
||||||
|
if (importance == NotificationManagerCompat.IMPORTANCE_NONE) {
|
||||||
|
Log.e(
|
||||||
|
"$TAG Keep alive for third party accounts Service channel has been disabled, can't start foreground service!"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val service = keepAliveService
|
||||||
|
if (service != null) {
|
||||||
|
val builder = NotificationCompat.Builder(context, channelId)
|
||||||
|
.setContentTitle(context.getString(R.string.app_name))
|
||||||
|
.setSmallIcon(R.drawable.linphone_notification)
|
||||||
|
.setAutoCancel(false)
|
||||||
|
.setOngoing(true)
|
||||||
|
.setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||||
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
|
.setShowWhen(false)
|
||||||
|
val notification = builder.build()
|
||||||
|
|
||||||
|
Log.i(
|
||||||
|
"$TAG Keep alive for third party accounts Service found, starting it as foreground using notification ID [$KEEP_ALIVE_FOR_THIRD_PARTY_ACCOUNTS_ID] with type DATA_SYNC"
|
||||||
|
)
|
||||||
|
Compatibility.startServiceForeground(
|
||||||
|
service,
|
||||||
|
KEEP_ALIVE_FOR_THIRD_PARTY_ACCOUNTS_ID,
|
||||||
|
notification,
|
||||||
|
Compatibility.FOREGROUND_SERVICE_TYPE_DATA_SYNC
|
||||||
|
)
|
||||||
|
currentKeepAliveThirdPartyAccountsForegroundServiceNotificationId = KEEP_ALIVE_FOR_THIRD_PARTY_ACCOUNTS_ID
|
||||||
|
} else {
|
||||||
|
Log.w("$TAG Keep alive for third party accounts Service hasn't started yet...")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainThread
|
||||||
|
private fun stopKeepAliveServiceForeground() {
|
||||||
|
val service = keepAliveService
|
||||||
|
if (service != null) {
|
||||||
|
Log.i(
|
||||||
|
"$TAG Stopping keep alive for third party accounts foreground Service (was using notification ID [$currentKeepAliveThirdPartyAccountsForegroundServiceNotificationId])"
|
||||||
|
)
|
||||||
|
service.stopForeground(STOP_FOREGROUND_REMOVE)
|
||||||
|
service.stopSelf()
|
||||||
|
currentKeepAliveThirdPartyAccountsForegroundServiceNotificationId = -1
|
||||||
|
} else {
|
||||||
|
Log.w(
|
||||||
|
"$TAG Can't stop keep alive for third party accounts foreground Service & notif, no Service was found"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@MainThread
|
@MainThread
|
||||||
private fun createIncomingCallNotificationChannel() {
|
private fun createIncomingCallNotificationChannel() {
|
||||||
val id = context.getString(R.string.notification_channel_incoming_call_id)
|
val id = context.getString(R.string.notification_channel_incoming_call_id)
|
||||||
|
|
@ -1302,12 +1380,12 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainThread
|
@MainThread
|
||||||
private fun createServiceChannel() {
|
private fun createThirdPartyAccountKeepAliveServiceChannel() {
|
||||||
val id = context.getString(R.string.notification_channel_service_id)
|
val id = context.getString(R.string.notification_channel_service_id)
|
||||||
val name = context.getString(R.string.notification_channel_service_name)
|
val name = context.getString(R.string.notification_channel_service_name)
|
||||||
|
|
||||||
val channel = NotificationChannel(id, name, NotificationManager.IMPORTANCE_LOW).apply {
|
val channel = NotificationChannel(id, name, NotificationManager.IMPORTANCE_LOW).apply {
|
||||||
description = name
|
description = context.getString(R.string.notification_channel_service_desc)
|
||||||
}
|
}
|
||||||
notificationManager.createNotificationChannel(channel)
|
notificationManager.createNotificationChannel(channel)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,9 @@ class SettingsViewModel @UiThread constructor() : ViewModel() {
|
||||||
)
|
)
|
||||||
val availableThemesValues = arrayListOf(-1, 0, 1)
|
val availableThemesValues = arrayListOf(-1, 0, 1)
|
||||||
|
|
||||||
// Advanced setttings
|
// Advanced settings
|
||||||
|
val keepAliveThirdPartyAccountsService = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
val remoteProvisioningUrl = MutableLiveData<String>()
|
val remoteProvisioningUrl = MutableLiveData<String>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
@ -159,6 +161,8 @@ class SettingsViewModel @UiThread constructor() : ViewModel() {
|
||||||
|
|
||||||
theme.postValue(corePreferences.darkMode)
|
theme.postValue(corePreferences.darkMode)
|
||||||
|
|
||||||
|
keepAliveThirdPartyAccountsService.postValue(corePreferences.keepServiceAlive)
|
||||||
|
|
||||||
remoteProvisioningUrl.postValue(core.provisioningUri)
|
remoteProvisioningUrl.postValue(core.provisioningUri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -356,6 +360,21 @@ class SettingsViewModel @UiThread constructor() : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
fun toggleKeepAliveThirdPartyAccountService() {
|
||||||
|
val newValue = keepAliveThirdPartyAccountsService.value == false
|
||||||
|
|
||||||
|
coreContext.postOnCoreThread {
|
||||||
|
corePreferences.keepServiceAlive = newValue
|
||||||
|
keepAliveThirdPartyAccountsService.postValue(newValue)
|
||||||
|
if (newValue) {
|
||||||
|
coreContext.startKeepAliveService()
|
||||||
|
} else {
|
||||||
|
coreContext.stopKeepAliveService()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
fun updateRemoteProvisioningUrl() {
|
fun updateRemoteProvisioningUrl() {
|
||||||
coreContext.postOnCoreThread { core ->
|
coreContext.postOnCoreThread { core ->
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,33 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.materialswitch.MaterialSwitch
|
||||||
|
style="@style/material_switch_style"
|
||||||
|
android:id="@+id/keep_alive_service_switch"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:checked="@{viewModel.keepAliveThirdPartyAccountsService}"
|
||||||
|
android:onClick="@{() -> viewModel.toggleKeepAliveThirdPartyAccountService()}"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
style="@style/header_style"
|
||||||
|
android:id="@+id/push_notifications_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:text="@string/settings_advanced_keep_alive_service_title"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:ellipsize="end"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/keep_alive_service_switch"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/keep_alive_service_switch"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/keep_alive_service_switch"/>
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
style="@style/header_style"
|
style="@style/header_style"
|
||||||
android:id="@+id/remote_provisioning_label"
|
android:id="@+id/remote_provisioning_label"
|
||||||
|
|
@ -68,7 +95,7 @@
|
||||||
android:paddingBottom="8dp"
|
android:paddingBottom="8dp"
|
||||||
android:text="@string/settings_advanced_remote_provisioning_url"
|
android:text="@string/settings_advanced_remote_provisioning_url"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"/>
|
app:layout_constraintTop_toBottomOf="@id/keep_alive_service_switch"/>
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatEditText
|
<androidx.appcompat.widget.AppCompatEditText
|
||||||
style="@style/default_text_style"
|
style="@style/default_text_style"
|
||||||
|
|
@ -91,6 +118,8 @@
|
||||||
app:layout_constraintStart_toStartOf="@id/remote_provisioning_label"
|
app:layout_constraintStart_toStartOf="@id/remote_provisioning_label"
|
||||||
app:layout_constraintEnd_toEndOf="parent"/>
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
|
<!-- TODO: apply button ? -->
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@
|
||||||
<string name="notification_channel_incoming_call_name">&appName; notifications d\'appels entrants</string>
|
<string name="notification_channel_incoming_call_name">&appName; notifications d\'appels entrants</string>
|
||||||
<string name="notification_channel_missed_call_name">&appName; notifications d\'appels manqués</string>
|
<string name="notification_channel_missed_call_name">&appName; notifications d\'appels manqués</string>
|
||||||
<string name="notification_channel_service_name">&appName; notification de service</string>
|
<string name="notification_channel_service_name">&appName; notification de service</string>
|
||||||
|
<string name="notification_channel_service_desc">Ce service sera actif en permanence pour garder l\'app en vie et vous permettre de recevoir appels et messages sans recourir aux notifications push.</string>
|
||||||
<string name="notification_channel_chat_name">&appName; notifications des conversations</string>
|
<string name="notification_channel_chat_name">&appName; notifications des conversations</string>
|
||||||
<string name="notification_chat_message_reaction_received">A réagi par %s à : %s</string>
|
<string name="notification_chat_message_reaction_received">A réagi par %s à : %s</string>
|
||||||
<string name="notification_mark_message_as_read">Marquer comme lu</string>
|
<string name="notification_mark_message_as_read">Marquer comme lu</string>
|
||||||
|
|
@ -256,7 +257,10 @@
|
||||||
<string name="settings_user_interface_dark_theme_label">Sombre</string>
|
<string name="settings_user_interface_dark_theme_label">Sombre</string>
|
||||||
<string name="settings_user_interface_light_theme_label">Clair</string>
|
<string name="settings_user_interface_light_theme_label">Clair</string>
|
||||||
<string name="settings_user_interface_auto_theme_label">Auto</string>
|
<string name="settings_user_interface_auto_theme_label">Auto</string>
|
||||||
|
|
||||||
<string name="settings_advanced_title">Paramètres avancés</string>
|
<string name="settings_advanced_title">Paramètres avancés</string>
|
||||||
|
<string name="settings_advanced_keep_alive_service_title">Garder l\'app en vie via un Service</string>
|
||||||
|
<string name="settings_advanced_remote_provisioning_url">URL de configuration distante</string>
|
||||||
|
|
||||||
<!-- Account profile & settings -->
|
<!-- Account profile & settings -->
|
||||||
<string name="manage_account_title">Votre compte</string>
|
<string name="manage_account_title">Votre compte</string>
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@
|
||||||
<string name="notification_channel_incoming_call_name">&appName; incoming calls notifications</string>
|
<string name="notification_channel_incoming_call_name">&appName; incoming calls notifications</string>
|
||||||
<string name="notification_channel_missed_call_name">&appName; missed calls notifications</string>
|
<string name="notification_channel_missed_call_name">&appName; missed calls notifications</string>
|
||||||
<string name="notification_channel_service_name">&appName; service notification</string>
|
<string name="notification_channel_service_name">&appName; service notification</string>
|
||||||
|
<string name="notification_channel_service_desc">This service will run all the time to keep app alive and allow you to receive calls and messages without push notifications.</string>
|
||||||
<string name="notification_channel_chat_name">&appName; instant messages notifications</string>
|
<string name="notification_channel_chat_name">&appName; instant messages notifications</string>
|
||||||
<string name="notification_chat_message_reaction_received">Reacted by %s to: %s</string>
|
<string name="notification_chat_message_reaction_received">Reacted by %s to: %s</string>
|
||||||
<string name="notification_mark_message_as_read">Mark as read</string>
|
<string name="notification_mark_message_as_read">Mark as read</string>
|
||||||
|
|
@ -291,8 +292,9 @@
|
||||||
<string name="settings_user_interface_dark_theme_label">Dark theme</string>
|
<string name="settings_user_interface_dark_theme_label">Dark theme</string>
|
||||||
<string name="settings_user_interface_light_theme_label">Light theme</string>
|
<string name="settings_user_interface_light_theme_label">Light theme</string>
|
||||||
<string name="settings_user_interface_auto_theme_label">Auto</string>
|
<string name="settings_user_interface_auto_theme_label">Auto</string>
|
||||||
<string name="settings_advanced_title">Advanced settings</string>
|
|
||||||
|
|
||||||
|
<string name="settings_advanced_title">Advanced settings</string>
|
||||||
|
<string name="settings_advanced_keep_alive_service_title">Keep app alive using Service</string>
|
||||||
<string name="settings_advanced_remote_provisioning_url">Remote provisioning URL</string>
|
<string name="settings_advanced_remote_provisioning_url">Remote provisioning URL</string>
|
||||||
|
|
||||||
<!-- Account profile & settings -->
|
<!-- Account profile & settings -->
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue