mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-17 11:28:06 +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>
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".core.CoreKeepAliveThirdPartyAccountsService"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="dataSync"
|
||||
android:stopWithTask="false"
|
||||
android:label="@string/app_name" />
|
||||
|
||||
<!-- Receivers -->
|
||||
|
||||
<receiver android:name=".core.CorePushReceiver"
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import android.app.Activity
|
|||
import android.app.Notification
|
||||
import android.app.PictureInPictureParams
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.provider.MediaStore
|
||||
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 {
|
||||
val params = PictureInPictureParams.Builder()
|
||||
.setAspectRatio(AppUtils.getPipRatio(activity))
|
||||
|
|
|
|||
|
|
@ -20,9 +20,11 @@
|
|||
package org.linphone.compatibility
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.ForegroundServiceStartNotAllowedException
|
||||
import android.app.PictureInPictureParams
|
||||
import android.app.UiModeManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.RenderEffect
|
||||
import android.graphics.Shader
|
||||
import android.os.Build
|
||||
|
|
@ -78,5 +80,17 @@ class Api31Compatibility {
|
|||
}
|
||||
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 {
|
||||
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_CAMERA = 64 // Matches ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA
|
||||
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) {
|
||||
if (Version.sdkAboveOrEqual(Version.API31_ANDROID_12)) {
|
||||
Api31Compatibility.setBlurRenderEffect(view)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import androidx.lifecycle.MutableLiveData
|
|||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import org.linphone.BuildConfig
|
||||
import org.linphone.LinphoneApplication.Companion.corePreferences
|
||||
import org.linphone.compatibility.Compatibility
|
||||
import org.linphone.contacts.ContactsManager
|
||||
import org.linphone.core.tools.Log
|
||||
import org.linphone.notifications.NotificationsManager
|
||||
|
|
@ -279,6 +280,10 @@ class CoreContext @UiThread constructor(val context: Context) : HandlerThread("C
|
|||
corePreferences.linphoneConfigurationVersion = CorePreferences.CURRENT_VERSION
|
||||
|
||||
Log.i("$TAG Report Core created and started")
|
||||
|
||||
if (corePreferences.keepServiceAlive) {
|
||||
startKeepAliveService()
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
|
|
@ -529,6 +534,30 @@ class CoreContext @UiThread constructor(val context: Context) : HandlerThread("C
|
|||
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
|
||||
fun updateFriendListsSubscriptionDependingOnDefaultAccount() {
|
||||
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)
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
@get:WorkerThread @set:WorkerThread
|
||||
|
|
@ -104,6 +111,7 @@ class CorePreferences @UiThread constructor(private val context: Context) {
|
|||
|
||||
// Conversation settings
|
||||
|
||||
@get:WorkerThread @set:WorkerThread
|
||||
var exportMediaToNativeGallery: Boolean // TODO: use it!
|
||||
// Keep old name for backward compatibility
|
||||
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 */
|
||||
|
||||
@get:WorkerThread @set:WorkerThread
|
||||
var voiceRecordingMaxDuration: Int
|
||||
get() = config.getInt("app", "voice_recording_max_duration", 600000) // in ms
|
||||
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.Core
|
||||
import org.linphone.core.CoreForegroundService
|
||||
import org.linphone.core.CoreKeepAliveThirdPartyAccountsService
|
||||
import org.linphone.core.CoreListenerStub
|
||||
import org.linphone.core.CorePreferences
|
||||
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"
|
||||
|
||||
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 var currentForegroundServiceNotificationId = -1
|
||||
private var currentKeepAliveThirdPartyAccountsForegroundServiceNotificationId = -1
|
||||
|
||||
private var currentlyRingingCallRemoteAddress: Address? = null
|
||||
|
||||
|
|
@ -137,7 +140,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
|||
val notifiable = getNotifiableForCall(call)
|
||||
if (notifiable.notificationId == currentForegroundServiceNotificationId) {
|
||||
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)
|
||||
}
|
||||
|
|
@ -349,6 +352,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
|||
}
|
||||
|
||||
private var coreService: CoreForegroundService? = null
|
||||
private var keepAliveService: CoreKeepAliveThirdPartyAccountsService? = null
|
||||
|
||||
private val callNotificationsMap: HashMap<String, Notifiable> = HashMap()
|
||||
private val chatNotificationsMap: HashMap<String, Notifiable> = HashMap()
|
||||
|
|
@ -397,7 +401,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
|||
stopCallForeground()
|
||||
} else if (currentForegroundServiceNotificationId == -1) {
|
||||
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()
|
||||
startCallForeground(call)
|
||||
|
|
@ -411,6 +415,20 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
|||
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
|
||||
private fun createChannels(clearPreviousChannels: Boolean) {
|
||||
if (clearPreviousChannels) {
|
||||
|
|
@ -421,7 +439,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
|||
}
|
||||
}
|
||||
|
||||
createServiceChannel()
|
||||
createThirdPartyAccountKeepAliveServiceChannel()
|
||||
createIncomingCallNotificationChannel()
|
||||
createMissedCallNotificationChannel()
|
||||
createActiveCallNotificationChannel()
|
||||
|
|
@ -608,7 +626,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
|||
) {
|
||||
mask = mask or Compatibility.FOREGROUND_SERVICE_TYPE_MICROPHONE
|
||||
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) {
|
||||
|
|
@ -623,7 +641,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
|||
) {
|
||||
mask = mask or Compatibility.FOREGROUND_SERVICE_TYPE_CAMERA
|
||||
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
|
||||
if (service != null) {
|
||||
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.stopSelf()
|
||||
currentForegroundServiceNotificationId = -1
|
||||
} 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) {
|
||||
// We can't notify using CallStyle if there isn't a foreground service running
|
||||
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 {
|
||||
Log.e("$TAG Illegal Argument Exception occurred: $iae")
|
||||
|
|
@ -1245,6 +1263,66 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
|||
.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
|
||||
private fun createIncomingCallNotificationChannel() {
|
||||
val id = context.getString(R.string.notification_channel_incoming_call_id)
|
||||
|
|
@ -1302,12 +1380,12 @@ class NotificationsManager @MainThread constructor(private val context: Context)
|
|||
}
|
||||
|
||||
@MainThread
|
||||
private fun createServiceChannel() {
|
||||
private fun createThirdPartyAccountKeepAliveServiceChannel() {
|
||||
val id = context.getString(R.string.notification_channel_service_id)
|
||||
val name = context.getString(R.string.notification_channel_service_name)
|
||||
|
||||
val channel = NotificationChannel(id, name, NotificationManager.IMPORTANCE_LOW).apply {
|
||||
description = name
|
||||
description = context.getString(R.string.notification_channel_service_desc)
|
||||
}
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,7 +115,9 @@ class SettingsViewModel @UiThread constructor() : ViewModel() {
|
|||
)
|
||||
val availableThemesValues = arrayListOf(-1, 0, 1)
|
||||
|
||||
// Advanced setttings
|
||||
// Advanced settings
|
||||
val keepAliveThirdPartyAccountsService = MutableLiveData<Boolean>()
|
||||
|
||||
val remoteProvisioningUrl = MutableLiveData<String>()
|
||||
|
||||
init {
|
||||
|
|
@ -159,6 +161,8 @@ class SettingsViewModel @UiThread constructor() : ViewModel() {
|
|||
|
||||
theme.postValue(corePreferences.darkMode)
|
||||
|
||||
keepAliveThirdPartyAccountsService.postValue(corePreferences.keepServiceAlive)
|
||||
|
||||
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
|
||||
fun updateRemoteProvisioningUrl() {
|
||||
coreContext.postOnCoreThread { core ->
|
||||
|
|
|
|||
|
|
@ -57,6 +57,33 @@
|
|||
android:layout_width="match_parent"
|
||||
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
|
||||
style="@style/header_style"
|
||||
android:id="@+id/remote_provisioning_label"
|
||||
|
|
@ -68,7 +95,7 @@
|
|||
android:paddingBottom="8dp"
|
||||
android:text="@string/settings_advanced_remote_provisioning_url"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
app:layout_constraintTop_toBottomOf="@id/keep_alive_service_switch"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatEditText
|
||||
style="@style/default_text_style"
|
||||
|
|
@ -91,6 +118,8 @@
|
|||
app:layout_constraintStart_toStartOf="@id/remote_provisioning_label"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
<!-- TODO: apply button ? -->
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
<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_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_chat_message_reaction_received">A réagi par %s à : %s</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_light_theme_label">Clair</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_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 -->
|
||||
<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_missed_call_name">&appName; missed calls notifications</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_chat_message_reaction_received">Reacted by %s to: %s</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_light_theme_label">Light theme</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>
|
||||
|
||||
<!-- Account profile & settings -->
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue