diff --git a/app/src/main/java/org/linphone/LinphoneApplication.kt b/app/src/main/java/org/linphone/LinphoneApplication.kt
index ac992ded0..47ac73384 100644
--- a/app/src/main/java/org/linphone/LinphoneApplication.kt
+++ b/app/src/main/java/org/linphone/LinphoneApplication.kt
@@ -70,7 +70,9 @@ class LinphoneApplication : Application(), ImageLoaderFactory {
val appName = context.getString(R.string.app_name)
Factory.instance().setLoggerDomain(appName)
Factory.instance().enableLogcatLogs(true)
- Factory.instance().loggingService.setLogLevel(LogLevel.Message)
+ if (corePreferences.debugLogs) {
+ Factory.instance().loggingService.setLogLevel(LogLevel.Message)
+ }
coreContext = CoreContext(context)
coreContext.start()
diff --git a/app/src/main/java/org/linphone/core/CorePreferences.kt b/app/src/main/java/org/linphone/core/CorePreferences.kt
index d0e600aee..3c4f92856 100644
--- a/app/src/main/java/org/linphone/core/CorePreferences.kt
+++ b/app/src/main/java/org/linphone/core/CorePreferences.kt
@@ -41,6 +41,13 @@ class CorePreferences @UiThread constructor(private val context: Context) {
_config = value
}
+ @get:WorkerThread @set:WorkerThread
+ var debugLogs: Boolean
+ get() = config.getBool("app", "debug", org.linphone.BuildConfig.DEBUG)
+ set(value) {
+ config.setBool("app", "debug", value)
+ }
+
@get:WorkerThread @set:WorkerThread
var conditionsAndPrivacyPolicyAccepted: Boolean
get() = config.getBool("app", "read_and_agree_terms_and_privacy", false)
diff --git a/app/src/main/java/org/linphone/ui/assistant/fragment/LoginFragment.kt b/app/src/main/java/org/linphone/ui/assistant/fragment/LoginFragment.kt
index 19daa71bc..4de0da4f1 100644
--- a/app/src/main/java/org/linphone/ui/assistant/fragment/LoginFragment.kt
+++ b/app/src/main/java/org/linphone/ui/assistant/fragment/LoginFragment.kt
@@ -83,12 +83,14 @@ class LoginFragment : Fragment() {
}
binding.setForgottenPasswordClickListener {
+ val url = getString(R.string.users_web_platform)
try {
- val url = "https://subscribe.linphone.org"
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(browserIntent)
} catch (ise: IllegalStateException) {
- Log.e("$TAG Can't start ACTION_VIEW intent, IllegalStateException: $ise")
+ Log.e(
+ "$TAG Can't start ACTION_VIEW intent for URL [$url], IllegalStateException: $ise"
+ )
}
}
@@ -199,28 +201,28 @@ class LoginFragment : Fragment() {
model.privacyPolicyClickedEvent.observe(viewLifecycleOwner) {
it.consume {
- val browserIntent = Intent(
- Intent.ACTION_VIEW,
- Uri.parse("https://www.linphone.org/privacy-policy")
- )
+ val url = getString(R.string.privacy_policy_url)
try {
+ val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(browserIntent)
- } catch (e: Exception) {
- Log.e("$TAG Can't start activity: $e")
+ } catch (ise: IllegalStateException) {
+ Log.e(
+ "$TAG Can't start ACTION_VIEW intent for URL [$url], IllegalStateException: $ise"
+ )
}
}
}
model.generalTermsClickedEvent.observe(viewLifecycleOwner) {
it.consume {
- val browserIntent = Intent(
- Intent.ACTION_VIEW,
- Uri.parse("https://www.linphone.org/general-terms")
- )
+ val url = getString(R.string.terms_and_conditions_url)
try {
+ val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(browserIntent)
- } catch (e: Exception) {
- Log.e("$TAG Can't start activity: $e")
+ } catch (ise: IllegalStateException) {
+ Log.e(
+ "$TAG Can't start ACTION_VIEW intent for URL [$url], IllegalStateException: $ise"
+ )
}
}
}
diff --git a/app/src/main/java/org/linphone/ui/assistant/fragment/RegisterFragment.kt b/app/src/main/java/org/linphone/ui/assistant/fragment/RegisterFragment.kt
index df959632f..0b015c778 100644
--- a/app/src/main/java/org/linphone/ui/assistant/fragment/RegisterFragment.kt
+++ b/app/src/main/java/org/linphone/ui/assistant/fragment/RegisterFragment.kt
@@ -85,12 +85,14 @@ class RegisterFragment : Fragment() {
}
binding.setOpenSubscribeWebPageClickListener {
+ val url = getString(R.string.users_web_platform)
try {
- val url = "https://subscribe.linphone.org"
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(browserIntent)
} catch (ise: IllegalStateException) {
- Log.e("$TAG Can't start ACTION_VIEW intent, IllegalStateException: $ise")
+ Log.e(
+ "$TAG Can't start ACTION_VIEW intent for URL [$url], IllegalStateException: $ise"
+ )
}
}
diff --git a/app/src/main/java/org/linphone/ui/assistant/fragment/ThirdPartySipAccountWarningFragment.kt b/app/src/main/java/org/linphone/ui/assistant/fragment/ThirdPartySipAccountWarningFragment.kt
index c1fdb2f64..39b783fa4 100644
--- a/app/src/main/java/org/linphone/ui/assistant/fragment/ThirdPartySipAccountWarningFragment.kt
+++ b/app/src/main/java/org/linphone/ui/assistant/fragment/ThirdPartySipAccountWarningFragment.kt
@@ -28,6 +28,7 @@ import android.view.ViewGroup
import androidx.annotation.UiThread
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
+import org.linphone.R
import org.linphone.core.tools.Log
import org.linphone.databinding.AssistantThirdPartySipAccountWarningFragmentBinding
@@ -58,12 +59,14 @@ class ThirdPartySipAccountWarningFragment : Fragment() {
}
binding.setContactClickListener {
+ val url = getString(R.string.website_contact_page)
try {
- val url = "https://linphone.org/contact"
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(browserIntent)
} catch (ise: IllegalStateException) {
- Log.e("$TAG Can't start ACTION_VIEW intent, IllegalStateException: $ise")
+ Log.e(
+ "$TAG Can't start ACTION_VIEW intent for URL [$url], IllegalStateException: $ise"
+ )
}
}
diff --git a/app/src/main/java/org/linphone/ui/main/MainActivity.kt b/app/src/main/java/org/linphone/ui/main/MainActivity.kt
index 19a34ce08..dd62cb59e 100644
--- a/app/src/main/java/org/linphone/ui/main/MainActivity.kt
+++ b/app/src/main/java/org/linphone/ui/main/MainActivity.kt
@@ -24,8 +24,6 @@ import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.Gravity
-import android.view.LayoutInflater
-import android.view.View
import android.view.ViewGroup
import androidx.annotation.DrawableRes
import androidx.annotation.UiThread
@@ -38,7 +36,7 @@ import androidx.navigation.findNavController
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.R
import org.linphone.databinding.MainActivityBinding
-import org.linphone.databinding.ToastBinding
+import org.linphone.utils.AppUtils
import org.linphone.utils.slideInToastFromTopForDuration
@UiThread
@@ -140,17 +138,7 @@ class MainActivity : AppCompatActivity() {
}
fun showGreenToast(message: String, @DrawableRes icon: Int) {
- val greenToast: ToastBinding = DataBindingUtil.inflate(
- LayoutInflater.from(this),
- R.layout.toast,
- binding.toastsArea,
- false
- )
- greenToast.message = message
- greenToast.icon = icon
- greenToast.shadowColor = R.drawable.shape_toast_green_shadow
- greenToast.textColor = R.color.green_online
- greenToast.root.visibility = View.GONE
+ val greenToast = AppUtils.getGreenToast(this, binding.toastsArea, message, icon)
binding.toastsArea.addView(greenToast.root)
greenToast.root.slideInToastFromTopForDuration(
@@ -159,6 +147,16 @@ class MainActivity : AppCompatActivity() {
)
}
+ fun showRedToast(message: String, @DrawableRes icon: Int) {
+ val redToast = AppUtils.getRedToast(this, binding.toastsArea, message, icon)
+ binding.toastsArea.addView(redToast.root)
+
+ redToast.root.slideInToastFromTopForDuration(
+ binding.toastsArea as ViewGroup,
+ lifecycleScope
+ )
+ }
+
private fun loadContacts() {
coreContext.contactsManager.loadContacts(this)
diff --git a/app/src/main/java/org/linphone/ui/main/settings/fragment/HelpFragment.kt b/app/src/main/java/org/linphone/ui/main/settings/fragment/HelpFragment.kt
index d5f1c5576..f471d7d76 100644
--- a/app/src/main/java/org/linphone/ui/main/settings/fragment/HelpFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/settings/fragment/HelpFragment.kt
@@ -1,17 +1,36 @@
package org.linphone.ui.main.settings.fragment
+import android.content.ClipData
+import android.content.ClipboardManager
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.UiThread
+import androidx.navigation.navGraphViewModels
+import org.linphone.R
+import org.linphone.core.tools.Log
import org.linphone.databinding.HelpFragmentBinding
+import org.linphone.ui.main.MainActivity
import org.linphone.ui.main.fragment.GenericFragment
+import org.linphone.ui.main.settings.viewmodel.HelpViewModel
+import org.linphone.utils.AppUtils
@UiThread
class HelpFragment : GenericFragment() {
+ companion object {
+ private const val TAG = "[Help Fragment]"
+ }
+
private lateinit var binding: HelpFragmentBinding
+ val viewModel: HelpViewModel by navGraphViewModels(
+ R.id.main_nav_graph
+ )
+
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -24,9 +43,109 @@ class HelpFragment : GenericFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.lifecycleOwner = viewLifecycleOwner
+ binding.viewModel = viewModel
binding.setBackClickListener {
goBack()
}
+
+ binding.setPrivacyPolicyClickListener {
+ val url = getString(R.string.privacy_policy_url)
+ try {
+ val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
+ startActivity(browserIntent)
+ } catch (ise: IllegalStateException) {
+ Log.e(
+ "$TAG Can't start ACTION_VIEW intent for URL [$url], IllegalStateException: $ise"
+ )
+ }
+ }
+
+ binding.setLicensesClickListener {
+ val url = getString(R.string.open_source_licences_usage_url)
+ try {
+ val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
+ startActivity(browserIntent)
+ } catch (ise: IllegalStateException) {
+ Log.e(
+ "$TAG Can't start ACTION_VIEW intent for URL [$url], IllegalStateException: $ise"
+ )
+ }
+ }
+
+ binding.setTranslateClickListener {
+ val url = getString(R.string.translate_weblate_url)
+ try {
+ val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
+ startActivity(browserIntent)
+ } catch (ise: IllegalStateException) {
+ Log.e(
+ "$TAG Can't start ACTION_VIEW intent for URL [$url], IllegalStateException: $ise"
+ )
+ }
+ }
+
+ viewModel.newVersionAvailableEvent.observe(viewLifecycleOwner) {
+ it.consume { version ->
+ (requireActivity() as MainActivity).showGreenToast(
+ getString(R.string.help_update_available_toast_message, version),
+ R.drawable.info
+ )
+ }
+ }
+
+ viewModel.versionUpToDateEvent.observe(viewLifecycleOwner) {
+ it.consume {
+ (requireActivity() as MainActivity).showGreenToast(
+ getString(R.string.help_version_up_to_date_toast_message),
+ R.drawable.info
+ )
+ }
+ }
+
+ viewModel.errorEvent.observe(viewLifecycleOwner) {
+ it.consume {
+ (requireActivity() as MainActivity).showRedToast(
+ getString(R.string.help_error_checking_version_toast_message),
+ R.drawable.warning_circle
+ )
+ }
+ }
+
+ viewModel.debugLogsCleanedEvent.observe(viewLifecycleOwner) {
+ it.consume {
+ (requireActivity() as MainActivity).showGreenToast(
+ getString(R.string.help_advanced_debug_logs_cleaned_toast_message),
+ R.drawable.info
+ )
+ }
+ }
+
+ viewModel.uploadDebugLogsFinishedEvent.observe(viewLifecycleOwner) {
+ it.consume { url ->
+ val clipboard =
+ requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+ val clip = ClipData.newPlainText("Logs url", url)
+ clipboard.setPrimaryClip(clip)
+
+ (requireActivity() as MainActivity).showGreenToast(
+ getString(
+ R.string.help_advanced_debug_logs_url_copied_into_clipboard_toast_message
+ ),
+ R.drawable.info
+ )
+
+ AppUtils.shareUploadedLogsUrl(requireActivity(), url)
+ }
+ }
+
+ viewModel.uploadDebugLogsErrorEvent.observe(viewLifecycleOwner) {
+ it.consume {
+ (requireActivity() as MainActivity).showRedToast(
+ getString(R.string.help_advanced_debug_logs_upload_error_toast_message),
+ R.drawable.warning_circle
+ )
+ }
+ }
}
}
diff --git a/app/src/main/java/org/linphone/ui/main/settings/viewmodel/HelpViewModel.kt b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/HelpViewModel.kt
new file mode 100644
index 000000000..1c8f328ae
--- /dev/null
+++ b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/HelpViewModel.kt
@@ -0,0 +1,172 @@
+/*
+ * 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 .
+ */
+package org.linphone.ui.main.settings.viewmodel
+
+import androidx.annotation.UiThread
+import androidx.annotation.WorkerThread
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import org.linphone.BuildConfig
+import org.linphone.LinphoneApplication.Companion.coreContext
+import org.linphone.LinphoneApplication.Companion.corePreferences
+import org.linphone.core.Core
+import org.linphone.core.CoreListenerStub
+import org.linphone.core.Factory
+import org.linphone.core.LogLevel
+import org.linphone.core.VersionUpdateCheckResult
+import org.linphone.core.tools.Log
+import org.linphone.utils.Event
+
+class HelpViewModel @UiThread constructor() : ViewModel() {
+ companion object {
+ private const val TAG = "[Help ViewModel]"
+ }
+
+ val version = MutableLiveData()
+
+ val debugModeEnabled = MutableLiveData()
+
+ val newVersionAvailableEvent: MutableLiveData> by lazy {
+ MutableLiveData>()
+ }
+
+ val versionUpToDateEvent: MutableLiveData> by lazy {
+ MutableLiveData>()
+ }
+
+ val errorEvent: MutableLiveData> by lazy {
+ MutableLiveData>()
+ }
+
+ val debugLogsCleanedEvent: MutableLiveData> by lazy {
+ MutableLiveData>()
+ }
+
+ val uploadDebugLogsFinishedEvent: MutableLiveData> by lazy {
+ MutableLiveData>()
+ }
+
+ val uploadDebugLogsErrorEvent: MutableLiveData> by lazy {
+ MutableLiveData>()
+ }
+
+ private val coreListener = object : CoreListenerStub() {
+ @WorkerThread
+ override fun onVersionUpdateCheckResultReceived(
+ core: Core,
+ result: VersionUpdateCheckResult,
+ version: String?,
+ url: String?
+ ) {
+ when (result) {
+ VersionUpdateCheckResult.NewVersionAvailable -> {
+ Log.i("$TAG Update available, version [$version], url [$url]")
+ if (!version.isNullOrEmpty()) {
+ newVersionAvailableEvent.postValue(Event(version))
+ }
+ }
+ VersionUpdateCheckResult.UpToDate -> {
+ Log.i("$TAG This version is up-to-date")
+ versionUpToDateEvent.postValue(Event(true))
+ }
+ else -> {
+ Log.e("$TAG Can't check for update, an error happened [$result]")
+ errorEvent.postValue(Event(true))
+ }
+ }
+ }
+
+ @WorkerThread
+ override fun onLogCollectionUploadStateChanged(
+ core: Core,
+ state: Core.LogCollectionUploadState,
+ info: String
+ ) {
+ Log.i("$TAG Logs upload state changed [$state]")
+ if (state == Core.LogCollectionUploadState.Delivered) {
+ uploadDebugLogsFinishedEvent.postValue(Event(info))
+ } else if (state == Core.LogCollectionUploadState.NotDelivered) {
+ uploadDebugLogsErrorEvent.postValue(Event(true))
+ }
+ }
+ }
+
+ init {
+ val currentVersion = BuildConfig.VERSION_NAME
+ version.value = currentVersion
+
+ coreContext.postOnCoreThread { core ->
+ core.addListener(coreListener)
+ debugModeEnabled.postValue(corePreferences.debugLogs)
+ }
+ }
+
+ @UiThread
+ override fun onCleared() {
+ super.onCleared()
+
+ coreContext.postOnCoreThread { core ->
+ core.removeListener(coreListener)
+ }
+ }
+
+ @UiThread
+ fun toggleDebugMode() {
+ val enabled = debugModeEnabled.value == false
+ debugModeEnabled.value = enabled
+
+ if (!enabled) {
+ cleanLogs()
+ }
+
+ coreContext.postOnCoreThread {
+ corePreferences.debugLogs = enabled
+ val logLevel = if (enabled) LogLevel.Message else LogLevel.Error
+ Factory.instance().loggingService.setLogLevel(logLevel)
+ Log.i("$TAG Debug logs have been ${if (enabled) "enabled" else "disabled"}")
+ }
+ }
+
+ @UiThread
+ fun cleanLogs() {
+ coreContext.postOnCoreThread { core ->
+ core.resetLogCollection()
+ Log.i("$TAG Debug logs have been cleaned")
+ debugLogsCleanedEvent.postValue(Event(true))
+ }
+ }
+
+ @UiThread
+ fun shareLogs() {
+ coreContext.postOnCoreThread { core ->
+ Log.i("$TAG Uploading debug logs for sharing")
+ core.uploadLogCollection()
+ }
+ }
+
+ @UiThread
+ fun checkForUpdate() {
+ val currentVersion = version.value.orEmpty()
+ coreContext.postOnCoreThread { core ->
+ Log.i("[$TAG] Checking for update using current version [$currentVersion]")
+ core.checkForUpdate(currentVersion)
+ }
+ }
+}
diff --git a/app/src/main/java/org/linphone/utils/AppUtils.kt b/app/src/main/java/org/linphone/utils/AppUtils.kt
index 644966462..2f3d1bfed 100644
--- a/app/src/main/java/org/linphone/utils/AppUtils.kt
+++ b/app/src/main/java/org/linphone/utils/AppUtils.kt
@@ -20,7 +20,9 @@
package org.linphone.utils
import android.app.Activity
+import android.content.ActivityNotFoundException
import android.content.Context
+import android.content.Intent
import android.util.DisplayMetrics
import android.util.Rational
import android.view.LayoutInflater
@@ -34,6 +36,7 @@ import androidx.annotation.StringRes
import androidx.databinding.DataBindingUtil
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.R
+import org.linphone.core.tools.Log
import org.linphone.databinding.ToastBinding
class AppUtils {
@@ -151,5 +154,29 @@ class AppUtils {
blueToast.root.visibility = View.GONE
return blueToast
}
+
+ @AnyThread
+ fun shareUploadedLogsUrl(activity: Activity, info: String) {
+ val appName = activity.getString(R.string.app_name)
+ val intent = Intent(Intent.ACTION_SEND)
+ intent.putExtra(
+ Intent.EXTRA_EMAIL,
+ arrayOf(activity.getString(R.string.help_advanced_send_debug_logs_email_address))
+ )
+ intent.putExtra(Intent.EXTRA_SUBJECT, "$appName Logs")
+ intent.putExtra(Intent.EXTRA_TEXT, info)
+ intent.type = "text/plain"
+
+ try {
+ activity.startActivity(
+ Intent.createChooser(
+ intent,
+ activity.getString(R.string.help_advanced_share_logs_dialog_title)
+ )
+ )
+ } catch (ex: ActivityNotFoundException) {
+ Log.e(ex)
+ }
+ }
}
}
diff --git a/app/src/main/res/drawable/file_text.xml b/app/src/main/res/drawable/file_text.xml
new file mode 100644
index 000000000..da26bb18b
--- /dev/null
+++ b/app/src/main/res/drawable/file_text.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/globe_hemisphere_west.xml b/app/src/main/res/drawable/globe_hemisphere_west.xml
new file mode 100644
index 000000000..6390028f6
--- /dev/null
+++ b/app/src/main/res/drawable/globe_hemisphere_west.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/wrench.xml b/app/src/main/res/drawable/wrench.xml
new file mode 100644
index 000000000..6c926c018
--- /dev/null
+++ b/app/src/main/res/drawable/wrench.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/assistant_login_fragment.xml b/app/src/main/res/layout/assistant_login_fragment.xml
index 6793cd5bb..c5ae6cf7c 100644
--- a/app/src/main/res/layout/assistant_login_fragment.xml
+++ b/app/src/main/res/layout/assistant_login_fragment.xml
@@ -304,7 +304,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:layout_marginStart="20dp"
- android:layout_marginBottom="20dp"
+ android:layout_marginBottom="32dp"
android:paddingTop="@dimen/primary_secondary_buttons_label_padding"
android:paddingBottom="@dimen/primary_secondary_buttons_label_padding"
android:paddingStart="20dp"
@@ -314,6 +314,7 @@
android:textColor="@color/secondary_button_label_color"
android:gravity="center"
android:background="@drawable/secondary_button_background"
+ app:layout_constraintVertical_bias="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/no_account_yet"
app:layout_constraintTop_toBottomOf="@id/third_party_sip_account"
diff --git a/app/src/main/res/layout/assistant_register_fragment.xml b/app/src/main/res/layout/assistant_register_fragment.xml
index cc0794ba0..1e5add134 100644
--- a/app/src/main/res/layout/assistant_register_fragment.xml
+++ b/app/src/main/res/layout/assistant_register_fragment.xml
@@ -33,7 +33,8 @@
+ android:layout_height="match_parent"
+ android:fillViewport="true">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/dimen.xml b/app/src/main/res/values/dimen.xml
index a72af6d12..27c15034a 100644
--- a/app/src/main/res/values/dimen.xml
+++ b/app/src/main/res/values/dimen.xml
@@ -28,6 +28,7 @@
55dp
70dp
+ 5dp
28dp
48dp
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 89b7ba198..63d06b6bd 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -14,6 +14,17 @@
linphone_notification_incoming_call_id
linphone_notification_service_id
+ GNU General Public License v3.0
+ © Belledonne Communications 2010-2023
+ linphone-android@belledonne-communications.com
+
+ https://linphone.org/contact
+ https://linphone.org/privacy-policy
+ https://linphone.org/general-terms
+ https://subscribe.linphone.org
+ https://weblate.linphone.org/
+ https://wiki.linphone.org/xwiki/wiki/public/view/Linphone/Third%20party%20components%20/#Hlinphone-android
+
SIP address
Display name
Domain
@@ -106,7 +117,26 @@
Settings
Recordings
+
Help
+ About &appName;
+ Privacy policy
+ What information &appName; collects and uses
+ Version
+ Check update
+ Contribute on &appName; translation
+ Advanced
+ Enable/disable debug logs
+ Blah
+ Clean logs
+ Share logs
+ Share debug logs link using…
+ A new version is available: %s
+ Your version is up-to-date
+ An error occurred while checking for update
+ Debug logs have been cleaned
+ Debug logs URL copied into clipboard
+ Failed to upload debug logs
Manage account
Details