Allow linphone-config URIs in QR codes scanned inside Linphone

This commit is contained in:
Sylvain Berfini 2025-12-11 10:25:46 +01:00
parent 618be9ee7c
commit d2b12159af
3 changed files with 46 additions and 24 deletions

View file

@ -19,7 +19,6 @@
*/
package org.linphone.ui.assistant.viewmodel
import android.util.Patterns
import androidx.annotation.UiThread
import androidx.annotation.WorkerThread
import androidx.lifecycle.MutableLiveData
@ -32,6 +31,7 @@ import org.linphone.ui.GenericViewModel
import org.linphone.utils.Event
import org.linphone.R
import org.linphone.core.GlobalState
import org.linphone.utils.LinphoneUtils
class QrCodeViewModel
@UiThread
@ -76,26 +76,27 @@ class QrCodeViewModel
if (result == null) {
showRedToast(R.string.assistant_qr_code_invalid_toast, R.drawable.warning_circle)
} else {
val isValidUrl = Patterns.WEB_URL.matcher(result).matches()
if (!isValidUrl) {
Log.e("$TAG The content of the QR Code doesn't seem to be a valid web URL")
val url = LinphoneUtils.getRemoteProvisioningUrlFromUri(result)
if (url == null) {
Log.e("$TAG The content of the QR Code [$result] doesn't seem to be a valid web URL")
showRedToast(R.string.assistant_qr_code_invalid_toast, R.drawable.warning_circle)
} else {
Log.i(
"$TAG QR code URL set, restarting the Core outside of iterate() loop to apply configuration changes"
)
core.nativePreviewWindowId = null
core.isVideoPreviewEnabled = false
core.isQrcodeVideoPreviewEnabled = false
core.provisioningUri = result
return
}
coreContext.postOnCoreThread { core ->
Log.i("$TAG Stopping Core")
coreContext.core.stop()
Log.i("$TAG Core has been stopped, restarting it")
coreContext.core.start()
Log.i("$TAG Core has been restarted")
}
Log.i(
"$TAG Setting QR code URL [$url], restarting the Core outside of iterate() loop to apply configuration changes"
)
core.nativePreviewWindowId = null
core.isVideoPreviewEnabled = false
core.isQrcodeVideoPreviewEnabled = false
core.provisioningUri = url
coreContext.postOnCoreThread { core ->
Log.i("$TAG Stopping Core")
core.stop()
Log.i("$TAG Core has been stopped, restarting it")
core.start()
Log.i("$TAG Core has been restarted")
}
}
}

View file

@ -790,11 +790,11 @@ class MainActivity : GenericActivity() {
}
private fun handleConfigIntent(uri: String) {
val remoteConfigUri = uri.substring("linphone-config:".length)
val url = when {
remoteConfigUri.startsWith("http://") || remoteConfigUri.startsWith("https://") -> remoteConfigUri
remoteConfigUri.startsWith("file://") -> remoteConfigUri
else -> "https://$remoteConfigUri"
Log.i("$TAG Trying to parse config intent [$uri] as remote provisioning URL")
val url = LinphoneUtils.getRemoteProvisioningUrlFromUri(uri)
if (url == null) {
Log.e("$TAG Couldn't parse URI [$uri] into a valid remote provisioning URL, aborting")
return
}
coreContext.postOnCoreThread { core ->

View file

@ -23,6 +23,7 @@ import android.graphics.Typeface
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.style.StyleSpan
import android.util.Patterns
import androidx.annotation.AnyThread
import androidx.annotation.DrawableRes
import androidx.annotation.IntegerRes
@ -65,6 +66,26 @@ class LinphoneUtils {
const val RECORDING_MKV_FILE_EXTENSION = ".mkv"
const val RECORDING_SMFF_FILE_EXTENSION = ".smff"
@AnyThread
fun getRemoteProvisioningUrlFromUri(uri: String): String? {
val linphoneScheme = "linphone-config:"
return if (uri.startsWith(linphoneScheme)) {
val remoteConfigUri = uri.substring(linphoneScheme.length)
val url = when {
remoteConfigUri.startsWith("http://") || remoteConfigUri.startsWith("https://") -> remoteConfigUri
remoteConfigUri.startsWith("file://") -> remoteConfigUri
else -> "https://$remoteConfigUri"
}
url
} else {
val isValidUrl = Patterns.WEB_URL.matcher(uri).matches()
if (!isValidUrl) {
return null
}
uri
}
}
@WorkerThread
fun getDefaultAccount(): Account? {
return coreContext.core.defaultAccount ?: coreContext.core.accountList.firstOrNull()