From 6bb6daadbaa8c0792d62bb998a82dea77aeec60f Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 24 Feb 2023 14:53:50 +0100 Subject: [PATCH] Switched account creator to FlexiAPI backend instead of XMLRPC --- CHANGELOG.md | 2 + app/src/main/assets/linphonerc_factory | 8 +- .../org/linphone/activities/Navigation.kt | 10 + .../fragments/AbstractPhoneFragment.kt | 4 +- .../fragments/AccountLoginFragment.kt | 4 - .../fragments/NoPushWarningFragment.kt | 36 ++++ .../assistant/fragments/WelcomeFragment.kt | 26 ++- .../viewmodels/AbstractPhoneViewModel.kt | 8 +- .../viewmodels/AbstractPushTokenViewModel.kt | 143 ++++++++++++++ .../viewmodels/AccountLoginViewModel.kt | 186 +++++++++++------- .../EmailAccountCreationViewModel.kt | 40 +++- .../EmailAccountValidationViewModel.kt | 36 ++-- .../viewmodels/GenericLoginViewModel.kt | 33 ++-- .../PhoneAccountCreationViewModel.kt | 74 ++++++- .../PhoneAccountLinkingViewModel.kt | 16 +- .../PhoneAccountValidationViewModel.kt | 20 +- .../fragments/ChatRoomCreationFragment.kt | 3 +- .../main/dialer/fragments/DialerFragment.kt | 3 +- .../viewmodels/AccountSettingsViewModel.kt | 7 +- .../java/org/linphone/core/CoreContext.kt | 14 +- .../java/org/linphone/utils/LinphoneUtils.kt | 14 ++ .../assistant_account_login_fragment.xml | 9 +- ...sistant_generic_account_login_fragment.xml | 2 +- .../assistant_no_push_warning_fragment.xml | 58 ++++++ ...istant_phone_account_creation_fragment.xml | 43 +++- ...sistant_phone_account_linking_fragment.xml | 10 +- .../res/layout/settings_account_fragment.xml | 1 + .../res/navigation/assistant_nav_graph.xml | 8 + app/src/main/res/values-fr/strings.xml | 5 +- app/src/main/res/values/strings.xml | 9 +- 30 files changed, 653 insertions(+), 179 deletions(-) create mode 100644 app/src/main/java/org/linphone/activities/assistant/fragments/NoPushWarningFragment.kt create mode 100644 app/src/main/java/org/linphone/activities/assistant/viewmodels/AbstractPushTokenViewModel.kt create mode 100644 app/src/main/res/layout/assistant_no_push_warning_fragment.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index bffe7e998..9adf7ea4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ Group changes to describe their impact on the project, as follows: - SIP URI in call can be selected using long press ### Changed +- Switched Account Creator backend from XMLRPC to FlexiAPI, it now requires to be able to receive a push notification +- Email account creation form is now only available if TELEPHONY feature is not available, not related to screen size anymore - Account EXPIRES is now set to 1 month instead of 1 year for sip.linphone.org accounts - Replaced voice recordings file name by localized placeholder text, like for video conferences invitations - Decline incoming calls with Busy reason if there is at least another active call diff --git a/app/src/main/assets/linphonerc_factory b/app/src/main/assets/linphonerc_factory index ea03b557a..23e6571e4 100644 --- a/app/src/main/assets/linphonerc_factory +++ b/app/src/main/assets/linphonerc_factory @@ -42,11 +42,11 @@ activation_code_length=4 prefer_basic_chat_room=1 record_aware=1 -[assistant] -xmlrpc_url=https://subscribe.linphone.org:444/wizard.php - [account_creator] -backend=0 +backend=1 +# 1 means FlexiAPI, 0 is XMLRPC +url=https://subscribe.linphone.org/api/ +# replace above URL by https://staging-subscribe.linphone.org/api/ for testing [lime] lime_update_threshold=86400 diff --git a/app/src/main/java/org/linphone/activities/Navigation.kt b/app/src/main/java/org/linphone/activities/Navigation.kt index 96bd4c815..84abc8c3b 100644 --- a/app/src/main/java/org/linphone/activities/Navigation.kt +++ b/app/src/main/java/org/linphone/activities/Navigation.kt @@ -1057,6 +1057,16 @@ internal fun WelcomeFragment.navigateToPhoneAccountCreation() { } } +internal fun WelcomeFragment.navigateToNoPushWarning() { + if (findNavController().currentDestination?.id == R.id.welcomeFragment) { + findNavController().navigate( + R.id.action_welcomeFragment_to_noPushWarningFragment, + null, + popupTo() + ) + } +} + internal fun WelcomeFragment.navigateToAccountLogin() { if (findNavController().currentDestination?.id == R.id.welcomeFragment) { findNavController().navigate( diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/AbstractPhoneFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/AbstractPhoneFragment.kt index f355ef69c..01c33748a 100644 --- a/app/src/main/java/org/linphone/activities/assistant/fragments/AbstractPhoneFragment.kt +++ b/app/src/main/java/org/linphone/activities/assistant/fragments/AbstractPhoneFragment.kt @@ -28,6 +28,7 @@ import org.linphone.activities.GenericFragment import org.linphone.activities.assistant.viewmodels.AbstractPhoneViewModel import org.linphone.compatibility.Compatibility import org.linphone.core.tools.Log +import org.linphone.utils.LinphoneUtils import org.linphone.utils.PermissionHelper import org.linphone.utils.PhoneNumberUtils @@ -55,7 +56,8 @@ abstract class AbstractPhoneFragment : GenericFragment() } protected fun checkPermissions() { - if (!resources.getBoolean(R.bool.isTablet)) { + // Only ask for phone number related permission on devices that have TELEPHONY feature && if push notifications are available + if (requireContext().packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) && LinphoneUtils.isPushNotificationAvailable()) { if (!PermissionHelper.get().hasReadPhoneStateOrPhoneNumbersPermission()) { Log.i("[Assistant] Asking for READ_PHONE_STATE/READ_PHONE_NUMBERS permission") Compatibility.requestReadPhoneStateOrNumbersPermission( diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/AccountLoginFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/AccountLoginFragment.kt index 2f23b4a5d..abee404c6 100644 --- a/app/src/main/java/org/linphone/activities/assistant/fragments/AccountLoginFragment.kt +++ b/app/src/main/java/org/linphone/activities/assistant/fragments/AccountLoginFragment.kt @@ -58,10 +58,6 @@ class AccountLoginFragment : AbstractPhoneFragment. + */ +package org.linphone.activities.assistant.fragments + +import android.os.Bundle +import android.view.View +import org.linphone.R +import org.linphone.activities.GenericFragment +import org.linphone.databinding.AssistantNoPushWarningFragmentBinding + +class NoPushWarningFragment : GenericFragment() { + override fun getLayoutId(): Int = R.layout.assistant_no_push_warning_fragment + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.lifecycleOwner = viewLifecycleOwner + } +} diff --git a/app/src/main/java/org/linphone/activities/assistant/fragments/WelcomeFragment.kt b/app/src/main/java/org/linphone/activities/assistant/fragments/WelcomeFragment.kt index 165cc99f8..79c54f64d 100644 --- a/app/src/main/java/org/linphone/activities/assistant/fragments/WelcomeFragment.kt +++ b/app/src/main/java/org/linphone/activities/assistant/fragments/WelcomeFragment.kt @@ -20,6 +20,7 @@ package org.linphone.activities.assistant.fragments import android.content.Intent +import android.content.pm.PackageManager import android.net.Uri import android.os.Bundle import android.text.SpannableString @@ -30,6 +31,7 @@ import android.view.View import androidx.lifecycle.ViewModelProvider import java.util.UnknownFormatConversionException import java.util.regex.Pattern +import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.R import org.linphone.activities.* @@ -39,6 +41,7 @@ import org.linphone.activities.navigateToEmailAccountCreation import org.linphone.activities.navigateToRemoteProvisioning import org.linphone.core.tools.Log import org.linphone.databinding.AssistantWelcomeFragmentBinding +import org.linphone.utils.LinphoneUtils class WelcomeFragment : GenericFragment() { private lateinit var viewModel: WelcomeViewModel @@ -54,10 +57,27 @@ class WelcomeFragment : GenericFragment() { binding.viewModel = viewModel binding.setCreateAccountClickListener { - if (resources.getBoolean(R.bool.isTablet)) { - navigateToEmailAccountCreation() + if (LinphoneUtils.isPushNotificationAvailable()) { + Log.i("[Assistant] Core says push notifications are available") + val deviceHasTelephonyFeature = coreContext.context.packageManager.hasSystemFeature( + PackageManager.FEATURE_TELEPHONY + ) + if (!deviceHasTelephonyFeature) { + Log.i( + "[Assistant] Device doesn't have TELEPHONY feature, showing email based account creation" + ) + navigateToEmailAccountCreation() + } else { + Log.i( + "[Assistant] Device has TELEPHONY feature, showing phone based account creation" + ) + navigateToPhoneAccountCreation() + } } else { - navigateToPhoneAccountCreation() + Log.w( + "[Assistant] Failed to get push notification info, showing warning instead of phone based account creation" + ) + navigateToNoPushWarning() } } diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/AbstractPhoneViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/AbstractPhoneViewModel.kt index 714706d1d..aa7dd4a75 100644 --- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/AbstractPhoneViewModel.kt +++ b/app/src/main/java/org/linphone/activities/assistant/viewmodels/AbstractPhoneViewModel.kt @@ -21,15 +21,15 @@ package org.linphone.activities.assistant.viewmodels import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel +import kotlinx.coroutines.* import org.linphone.activities.assistant.fragments.CountryPickerFragment import org.linphone.core.AccountCreator import org.linphone.core.DialPlan import org.linphone.core.tools.Log import org.linphone.utils.PhoneNumberUtils -abstract class AbstractPhoneViewModel(val accountCreator: AccountCreator) : - ViewModel(), +abstract class AbstractPhoneViewModel(accountCreator: AccountCreator) : + AbstractPushTokenViewModel(accountCreator), CountryPickerFragment.CountryPickedListener { val prefix = MutableLiveData() @@ -71,7 +71,7 @@ abstract class AbstractPhoneViewModel(val accountCreator: AccountCreator) : } private fun getCountryNameFromPrefix(prefix: String?) { - if (prefix != null && prefix.isNotEmpty()) { + if (!prefix.isNullOrEmpty()) { val countryCode = if (prefix.first() == '+') prefix.substring(1) else prefix val dialPlan = PhoneNumberUtils.getDialPlanFromCountryCallingPrefix(countryCode) Log.i("[Assistant] Found dial plan $dialPlan from country code: $countryCode") diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/AbstractPushTokenViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/AbstractPushTokenViewModel.kt new file mode 100644 index 000000000..363475e63 --- /dev/null +++ b/app/src/main/java/org/linphone/activities/assistant/viewmodels/AbstractPushTokenViewModel.kt @@ -0,0 +1,143 @@ +/* + * 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.activities.assistant.viewmodels + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.json.JSONException +import org.json.JSONObject +import org.linphone.LinphoneApplication.Companion.coreContext +import org.linphone.core.AccountCreator +import org.linphone.core.Core +import org.linphone.core.CoreListenerStub +import org.linphone.core.tools.Log + +abstract class AbstractPushTokenViewModel(val accountCreator: AccountCreator) : ViewModel() { + private var waitingForPushToken = false + private var waitForPushJob: Job? = null + + private val coreListener = object : CoreListenerStub() { + override fun onPushNotificationReceived(core: Core, payload: String?) { + Log.i("[Assistant] Push received: [$payload]") + + val data = payload.orEmpty() + if (data.isNotEmpty()) { + try { + // This is because JSONObject.toString() done by the SDK will result in payload looking like {"custom-payload":"{\"token\":\"value\"}"} + val cleanPayload = data.replace("\\\"", "\"").replace("\"{", "{").replace( + "}\"", + "}" + ) + Log.i("[Assistant] Cleaned payload is: [$cleanPayload]") + val json = JSONObject(cleanPayload) + val customPayload = json.getJSONObject("custom-payload") + if (customPayload.has("token")) { + waitForPushJob?.cancel() + waitingForPushToken = false + + val token = customPayload.getString("token") + if (token.isNotEmpty()) { + Log.i("[Assistant] Extracted token [$token] from push payload") + accountCreator.token = token + onFlexiApiTokenReceived() + } else { + Log.e("[Assistant] Push payload JSON object has an empty 'token'!") + onFlexiApiTokenRequestError() + } + } else { + Log.e("[Assistant] Push payload JSON object has no 'token' key!") + onFlexiApiTokenRequestError() + } + } catch (e: JSONException) { + Log.e("[Assistant] Exception trying to parse push payload as JSON: [$e]") + onFlexiApiTokenRequestError() + } + } else { + Log.e("[Assistant] Push payload is null or empty, can't extract auth token!") + onFlexiApiTokenRequestError() + } + } + } + + init { + coreContext.core.addListener(coreListener) + } + + override fun onCleared() { + coreContext.core.removeListener(coreListener) + waitForPushJob?.cancel() + } + + abstract fun onFlexiApiTokenReceived() + abstract fun onFlexiApiTokenRequestError() + + protected fun requestFlexiApiToken() { + if (!coreContext.core.isPushNotificationAvailable) { + Log.e( + "[Assistant] Core says push notification aren't available, can't request a token from FlexiAPI" + ) + onFlexiApiTokenRequestError() + return + } + + val pushConfig = coreContext.core.pushNotificationConfig + if (pushConfig != null) { + Log.i( + "[Assistant] Found push notification info: provider [${pushConfig.provider}], param [${pushConfig.param}] and prid [${pushConfig.prid}]" + ) + accountCreator.pnProvider = pushConfig.provider + accountCreator.pnParam = pushConfig.param + accountCreator.pnPrid = pushConfig.prid + + // Request an auth token, will be sent by push + val result = accountCreator.requestAuthToken() + if (result == AccountCreator.Status.RequestOk) { + val waitFor = 5000 + waitingForPushToken = true + waitForPushJob?.cancel() + + Log.i("[Assistant] Waiting push with auth token for $waitFor ms") + waitForPushJob = viewModelScope.launch { + withContext(Dispatchers.IO) { + delay(waitFor.toLong()) + } + withContext(Dispatchers.Main) { + if (waitingForPushToken) { + waitingForPushToken = false + Log.e("[Assistant] Auth token wasn't received by push in $waitFor ms") + onFlexiApiTokenRequestError() + } + } + } + } else { + Log.e("[Assistant] Failed to require a push with an auth token: [$result]") + onFlexiApiTokenRequestError() + } + } else { + Log.e("[Assistant] No push configuration object in Core, shouldn't happen!") + onFlexiApiTokenRequestError() + } + } +} diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/AccountLoginViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/AccountLoginViewModel.kt index d74b17fa0..807ed80cc 100644 --- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/AccountLoginViewModel.kt +++ b/app/src/main/java/org/linphone/activities/assistant/viewmodels/AccountLoginViewModel.kt @@ -19,12 +19,13 @@ */ package org.linphone.activities.assistant.viewmodels +import android.content.pm.PackageManager import androidx.lifecycle.* import org.linphone.LinphoneApplication.Companion.coreContext -import org.linphone.R import org.linphone.core.* import org.linphone.core.tools.Log import org.linphone.utils.Event +import org.linphone.utils.LinphoneUtils import org.linphone.utils.PhoneNumberUtils class AccountLoginViewModelFactory(private val accountCreator: AccountCreator) : @@ -51,6 +52,8 @@ class AccountLoginViewModel(accountCreator: AccountCreator) : AbstractPhoneViewM val displayName = MutableLiveData() + val forceLoginUsingUsernameAndPassword = MutableLiveData() + val leaveAssistantEvent: MutableLiveData> by lazy { MutableLiveData>() } @@ -84,17 +87,16 @@ class AccountLoginViewModel(accountCreator: AccountCreator) : AbstractPhoneViewM } } - private var proxyConfigToCheck: ProxyConfig? = null + private var accountToCheck: Account? = null private val coreListener = object : CoreListenerStub() { - @Deprecated("Deprecated in Java") - override fun onRegistrationStateChanged( + override fun onAccountRegistrationStateChanged( core: Core, - cfg: ProxyConfig, - state: RegistrationState, + account: Account, + state: RegistrationState?, message: String ) { - if (cfg == proxyConfigToCheck) { + if (account == accountToCheck) { Log.i("[Assistant] [Account Login] Registration state is $state: $message") if (state == RegistrationState.Ok) { waitForServerAnswer.value = false @@ -112,7 +114,12 @@ class AccountLoginViewModel(accountCreator: AccountCreator) : AbstractPhoneViewM init { accountCreator.addListener(listener) - loginWithUsernamePassword.value = coreContext.context.resources.getBoolean(R.bool.isTablet) + val pushAvailable = LinphoneUtils.isPushNotificationAvailable() + val deviceHasTelephonyFeature = coreContext.context.packageManager.hasSystemFeature( + PackageManager.FEATURE_TELEPHONY + ) + loginWithUsernamePassword.value = !deviceHasTelephonyFeature || !pushAvailable + forceLoginUsingUsernameAndPassword.value = !pushAvailable loginEnabled.value = false loginEnabled.addSource(prefix) { @@ -140,76 +147,105 @@ class AccountLoginViewModel(accountCreator: AccountCreator) : AbstractPhoneViewM super.onCleared() } + override fun onFlexiApiTokenReceived() { + Log.i("[Assistant] [Account Login] Using FlexiAPI auth token [${accountCreator.token}]") + loginWithPhoneNumber() + } + + override fun onFlexiApiTokenRequestError() { + Log.e("[Assistant] [Account Login] Failed to get an auth token from FlexiAPI") + waitForServerAnswer.value = false + onErrorEvent.value = Event("Error: Failed to get an auth token from account manager server") + } + fun removeInvalidProxyConfig() { - val cfg = proxyConfigToCheck - cfg ?: return - val authInfo = cfg.findAuthInfo() + val account = accountToCheck + account ?: return + val authInfo = account.findAuthInfo() if (authInfo != null) coreContext.core.removeAuthInfo(authInfo) - coreContext.core.removeProxyConfig(cfg) - proxyConfigToCheck = null + coreContext.core.removeAccount(account) + accountToCheck = null } fun continueEvenIfInvalidCredentials() { leaveAssistantEvent.value = Event(true) } + private fun loginWithUsername() { + val result = accountCreator.setUsername(username.value) + if (result != AccountCreator.UsernameStatus.Ok) { + Log.e( + "[Assistant] [Account Login] Error [${result.name}] setting the username: ${username.value}" + ) + usernameError.value = result.name + return + } + Log.i("[Assistant] [Account Login] Username is ${accountCreator.username}") + + val result2 = accountCreator.setPassword(password.value) + if (result2 != AccountCreator.PasswordStatus.Ok) { + Log.e("[Assistant] [Account Login] Error [${result2.name}] setting the password") + passwordError.value = result2.name + return + } + + waitForServerAnswer.value = true + coreContext.core.addListener(coreListener) + if (!createAccountAndAuthInfo()) { + waitForServerAnswer.value = false + coreContext.core.removeListener(coreListener) + onErrorEvent.value = Event("Error: Failed to create account object") + } + } + + private fun loginWithPhoneNumber() { + val result = AccountCreator.PhoneNumberStatus.fromInt( + accountCreator.setPhoneNumber(phoneNumber.value, prefix.value) + ) + if (result != AccountCreator.PhoneNumberStatus.Ok) { + Log.e( + "[Assistant] [Account Login] Error [$result] setting the phone number: ${phoneNumber.value} with prefix: ${prefix.value}" + ) + phoneNumberError.value = result.name + return + } + Log.i("[Assistant] [Account Login] Phone number is ${accountCreator.phoneNumber}") + + val result2 = accountCreator.setUsername(accountCreator.phoneNumber) + if (result2 != AccountCreator.UsernameStatus.Ok) { + Log.e( + "[Assistant] [Account Login] Error [${result2.name}] setting the username: ${accountCreator.phoneNumber}" + ) + usernameError.value = result2.name + return + } + Log.i("[Assistant] [Account Login] Username is ${accountCreator.username}") + + waitForServerAnswer.value = true + val status = accountCreator.recoverAccount() + Log.i("[Assistant] [Account Login] Recover account returned $status") + if (status != AccountCreator.Status.RequestOk) { + waitForServerAnswer.value = false + onErrorEvent.value = Event("Error: ${status.name}") + } + } + fun login() { accountCreator.displayName = displayName.value if (loginWithUsernamePassword.value == true) { - val result = accountCreator.setUsername(username.value) - if (result != AccountCreator.UsernameStatus.Ok) { - Log.e( - "[Assistant] [Account Login] Error [${result.name}] setting the username: ${username.value}" - ) - usernameError.value = result.name - return - } - Log.i("[Assistant] [Account Login] Username is ${accountCreator.username}") - - val result2 = accountCreator.setPassword(password.value) - if (result2 != AccountCreator.PasswordStatus.Ok) { - Log.e("[Assistant] [Account Login] Error [${result2.name}] setting the password") - passwordError.value = result2.name - return - } - - waitForServerAnswer.value = true - coreContext.core.addListener(coreListener) - if (!createProxyConfig()) { - waitForServerAnswer.value = false - coreContext.core.removeListener(coreListener) - onErrorEvent.value = Event("Error: Failed to create account object") - } + loginWithUsername() } else { - val result = AccountCreator.PhoneNumberStatus.fromInt( - accountCreator.setPhoneNumber(phoneNumber.value, prefix.value) - ) - if (result != AccountCreator.PhoneNumberStatus.Ok) { - Log.e( - "[Assistant] [Account Login] Error [$result] setting the phone number: ${phoneNumber.value} with prefix: ${prefix.value}" + val token = accountCreator.token.orEmpty() + if (token.isNotEmpty()) { + Log.i( + "[Assistant] [Account Login] We already have an auth token from FlexiAPI [$token], continue" ) - phoneNumberError.value = result.name - return - } - Log.i("[Assistant] [Account Login] Phone number is ${accountCreator.phoneNumber}") - - val result2 = accountCreator.setUsername(accountCreator.phoneNumber) - if (result2 != AccountCreator.UsernameStatus.Ok) { - Log.e( - "[Assistant] [Account Login] Error [${result2.name}] setting the username: ${accountCreator.phoneNumber}" - ) - usernameError.value = result2.name - return - } - Log.i("[Assistant] [Account Login] Username is ${accountCreator.username}") - - waitForServerAnswer.value = true - val status = accountCreator.recoverAccount() - Log.i("[Assistant] [Account Login] Recover account returned $status") - if (status != AccountCreator.Status.RequestOk) { - waitForServerAnswer.value = false - onErrorEvent.value = Event("Error: ${status.name}") + onFlexiApiTokenReceived() + } else { + Log.i("[Assistant] [Account Login] Requesting an auth token from FlexiAPI") + waitForServerAnswer.value = true + requestFlexiApiToken() } } } @@ -222,33 +258,33 @@ class AccountLoginViewModel(accountCreator: AccountCreator) : AbstractPhoneViewM } } - private fun createProxyConfig(): Boolean { - val proxyConfig: ProxyConfig? = accountCreator.createProxyConfig() - proxyConfigToCheck = proxyConfig + private fun createAccountAndAuthInfo(): Boolean { + val account = accountCreator.createAccountInCore() + accountToCheck = account - if (proxyConfig == null) { - Log.e("[Assistant] [Account Login] Account creator couldn't create proxy config") + if (account == null) { + Log.e("[Assistant] [Account Login] Account creator couldn't create account") onErrorEvent.value = Event("Error: Failed to create account object") return false } - proxyConfig.isPushNotificationAllowed = true + val params = account.params.clone() + params.pushNotificationAllowed = true - if (proxyConfig.dialPrefix.isNullOrEmpty()) { + if (params.internationalPrefix.isNullOrEmpty()) { val dialPlan = PhoneNumberUtils.getDialPlanForCurrentCountry(coreContext.context) if (dialPlan != null) { Log.i( "[Assistant] [Account Login] Found dial plan country ${dialPlan.country} with international prefix ${dialPlan.countryCallingCode}" ) - proxyConfig.edit() - proxyConfig.dialPrefix = dialPlan.countryCallingCode - proxyConfig.done() + params.internationalPrefix = dialPlan.countryCallingCode } else { Log.w("[Assistant] [Account Login] Failed to find dial plan") } } - Log.i("[Assistant] [Account Login] Proxy config created") + account.params = params + Log.i("[Assistant] [Account Login] Account created") return true } } diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/EmailAccountCreationViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/EmailAccountCreationViewModel.kt index d3e1bde22..08b6f4ab7 100644 --- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/EmailAccountCreationViewModel.kt +++ b/app/src/main/java/org/linphone/activities/assistant/viewmodels/EmailAccountCreationViewModel.kt @@ -39,7 +39,9 @@ class EmailAccountCreationViewModelFactory(private val accountCreator: AccountCr } } -class EmailAccountCreationViewModel(val accountCreator: AccountCreator) : ViewModel() { +class EmailAccountCreationViewModel(accountCreator: AccountCreator) : AbstractPushTokenViewModel( + accountCreator +) { val username = MutableLiveData() val usernameError = MutableLiveData() @@ -70,7 +72,7 @@ class EmailAccountCreationViewModel(val accountCreator: AccountCreator) : ViewMo status: AccountCreator.Status, response: String? ) { - Log.i("[Assistant] [Account Creation] onIsAccountExist status is $status") + Log.i("[Account Creation] onIsAccountExist status is $status") when (status) { AccountCreator.Status.AccountExist, AccountCreator.Status.AccountExistWithAlias -> { waitForServerAnswer.value = false @@ -146,18 +148,40 @@ class EmailAccountCreationViewModel(val accountCreator: AccountCreator) : ViewMo super.onCleared() } + override fun onFlexiApiTokenReceived() { + Log.i("[Account Creation] Using FlexiAPI auth token [${accountCreator.token}]") + + waitForServerAnswer.value = true + val status = accountCreator.isAccountExist + Log.i("[Account Creation] Account exists returned $status") + if (status != AccountCreator.Status.RequestOk) { + waitForServerAnswer.value = false + onErrorEvent.value = Event("Error: ${status.name}") + } + } + + override fun onFlexiApiTokenRequestError() { + Log.e("[Account Creation] Failed to get an auth token from FlexiAPI") + waitForServerAnswer.value = false + onErrorEvent.value = Event("Error: Failed to get an auth token from account manager server") + } + fun create() { accountCreator.username = username.value accountCreator.password = password.value accountCreator.email = email.value accountCreator.displayName = displayName.value - waitForServerAnswer.value = true - val status = accountCreator.isAccountExist - Log.i("[Assistant] [Account Creation] Account exists returned $status") - if (status != AccountCreator.Status.RequestOk) { - waitForServerAnswer.value = false - onErrorEvent.value = Event("Error: ${status.name}") + val token = accountCreator.token.orEmpty() + if (token.isNotEmpty()) { + Log.i( + "[Account Creation] We already have an auth token from FlexiAPI [$token], continue" + ) + onFlexiApiTokenReceived() + } else { + Log.i("[Account Creation] Requesting an auth token from FlexiAPI") + waitForServerAnswer.value = true + requestFlexiApiToken() } } diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/EmailAccountValidationViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/EmailAccountValidationViewModel.kt index 856d11b10..52fffbb26 100644 --- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/EmailAccountValidationViewModel.kt +++ b/app/src/main/java/org/linphone/activities/assistant/viewmodels/EmailAccountValidationViewModel.kt @@ -22,11 +22,12 @@ package org.linphone.activities.assistant.viewmodels import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import org.linphone.LinphoneApplication +import org.linphone.LinphoneApplication.Companion.coreContext +import org.linphone.R import org.linphone.core.AccountCreator import org.linphone.core.AccountCreatorListenerStub -import org.linphone.core.ProxyConfig import org.linphone.core.tools.Log +import org.linphone.utils.AppUtils import org.linphone.utils.Event import org.linphone.utils.PhoneNumberUtils @@ -61,14 +62,16 @@ class EmailAccountValidationViewModel(val accountCreator: AccountCreator) : View when (status) { AccountCreator.Status.AccountActivated -> { - if (createProxyConfig()) { + if (createAccountAndAuthInfo()) { leaveAssistantEvent.value = Event(true) } else { onErrorEvent.value = Event("Error: ${status.name}") } } AccountCreator.Status.AccountNotActivated -> { - onErrorEvent.value = Event("Error: ${status.name}") + onErrorEvent.value = Event( + AppUtils.getString(R.string.assistant_create_email_account_not_validated) + ) } else -> { onErrorEvent.value = Event("Error: ${status.name}") @@ -97,34 +100,33 @@ class EmailAccountValidationViewModel(val accountCreator: AccountCreator) : View } } - private fun createProxyConfig(): Boolean { - val proxyConfig: ProxyConfig? = accountCreator.createProxyConfig() + private fun createAccountAndAuthInfo(): Boolean { + val account = accountCreator.createAccountInCore() - if (proxyConfig == null) { - Log.e("[Assistant] [Account Validation] Account creator couldn't create proxy config") + if (account == null) { + Log.e("[Assistant] [Account Validation] Account creator couldn't create account") onErrorEvent.value = Event("Error: Failed to create account object") return false } - proxyConfig.isPushNotificationAllowed = true + val params = account.params.clone() + params.pushNotificationAllowed = true - if (proxyConfig.dialPrefix.isNullOrEmpty()) { - val dialPlan = PhoneNumberUtils.getDialPlanForCurrentCountry( - LinphoneApplication.coreContext.context - ) + if (params.internationalPrefix.isNullOrEmpty()) { + val dialPlan = PhoneNumberUtils.getDialPlanForCurrentCountry(coreContext.context) if (dialPlan != null) { Log.i( "[Assistant] [Account Validation] Found dial plan country ${dialPlan.country} with international prefix ${dialPlan.countryCallingCode}" ) - proxyConfig.edit() - proxyConfig.dialPrefix = dialPlan.countryCallingCode - proxyConfig.done() + params.internationalPrefix = dialPlan.countryCallingCode } else { Log.w("[Assistant] [Account Validation] Failed to find dial plan") } } - Log.i("[Assistant] [Account Validation] Proxy config created") + account.params = params + + Log.i("[Assistant] [Account Validation] Account created") return true } } diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/GenericLoginViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/GenericLoginViewModel.kt index 3b1129cd3..0a6c75014 100644 --- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/GenericLoginViewModel.kt +++ b/app/src/main/java/org/linphone/activities/assistant/viewmodels/GenericLoginViewModel.kt @@ -62,17 +62,16 @@ class GenericLoginViewModel(private val accountCreator: AccountCreator) : ViewMo MutableLiveData>() } - private var proxyConfigToCheck: ProxyConfig? = null + private var accountToCheck: Account? = null private val coreListener = object : CoreListenerStub() { - @Deprecated("Deprecated in Java") - override fun onRegistrationStateChanged( + override fun onAccountRegistrationStateChanged( core: Core, - cfg: ProxyConfig, - state: RegistrationState, + account: Account, + state: RegistrationState?, message: String ) { - if (cfg == proxyConfigToCheck) { + if (account == accountToCheck) { Log.i("[Assistant] [Generic Login] Registration state is $state: $message") if (state == RegistrationState.Ok) { waitForServerAnswer.value = false @@ -107,19 +106,19 @@ class GenericLoginViewModel(private val accountCreator: AccountCreator) : ViewMo } fun removeInvalidProxyConfig() { - val cfg = proxyConfigToCheck - cfg ?: return - val authInfo = cfg.findAuthInfo() + val account = accountToCheck + account ?: return + val authInfo = account.findAuthInfo() if (authInfo != null) coreContext.core.removeAuthInfo(authInfo) - coreContext.core.removeProxyConfig(cfg) - proxyConfigToCheck = null + coreContext.core.removeAccount(account) + accountToCheck = null } fun continueEvenIfInvalidCredentials() { leaveAssistantEvent.value = Event(true) } - fun createProxyConfig() { + fun createAccountAndAuthInfo() { waitForServerAnswer.value = true coreContext.core.addListener(coreListener) @@ -129,18 +128,18 @@ class GenericLoginViewModel(private val accountCreator: AccountCreator) : ViewMo accountCreator.displayName = displayName.value accountCreator.transport = transport.value - val proxyConfig: ProxyConfig? = accountCreator.createProxyConfig() - proxyConfigToCheck = proxyConfig + val account = accountCreator.createAccountInCore() + accountToCheck = account - if (proxyConfig == null) { - Log.e("[Assistant] [Generic Login] Account creator couldn't create proxy config") + if (account == null) { + Log.e("[Assistant] [Generic Login] Account creator couldn't create account") coreContext.core.removeListener(coreListener) onErrorEvent.value = Event("Error: Failed to create account object") waitForServerAnswer.value = false return } - Log.i("[Assistant] [Generic Login] Proxy config created") + Log.i("[Assistant] [Generic Login] Account created") } private fun isLoginButtonEnabled(): Boolean { diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountCreationViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountCreationViewModel.kt index 46b249ff1..a857cd1c3 100644 --- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountCreationViewModel.kt +++ b/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountCreationViewModel.kt @@ -71,6 +71,36 @@ class PhoneAccountCreationViewModel(accountCreator: AccountCreator) : AbstractPh Log.i("[Phone Account Creation] onIsAccountExist status is $status") when (status) { AccountCreator.Status.AccountExist, AccountCreator.Status.AccountExistWithAlias -> { + waitForServerAnswer.value = false + usernameError.value = AppUtils.getString( + R.string.assistant_error_username_already_exists + ) + } + AccountCreator.Status.AccountNotExist -> { + waitForServerAnswer.value = false + checkPhoneNumber() + } + else -> { + waitForServerAnswer.value = false + onErrorEvent.value = Event("Error: ${status.name}") + } + } + } + + override fun onIsAliasUsed( + creator: AccountCreator, + status: AccountCreator.Status, + response: String? + ) { + Log.i("[Phone Account Creation] onIsAliasUsed status is $status") + when (status) { + AccountCreator.Status.AliasExist -> { + waitForServerAnswer.value = false + phoneNumberError.value = AppUtils.getString( + R.string.assistant_error_phone_number_already_exists + ) + } + AccountCreator.Status.AliasIsAccount -> { waitForServerAnswer.value = false if (useUsername.value == true) { usernameError.value = AppUtils.getString( @@ -82,7 +112,7 @@ class PhoneAccountCreationViewModel(accountCreator: AccountCreator) : AbstractPh ) } } - AccountCreator.Status.AccountNotExist -> { + AccountCreator.Status.AliasNotExist -> { val createAccountStatus = creator.createAccount() Log.i("[Phone Account Creation] createAccount returned $createAccountStatus") if (createAccountStatus != AccountCreator.Status.RequestOk) { @@ -150,16 +180,31 @@ class PhoneAccountCreationViewModel(accountCreator: AccountCreator) : AbstractPh super.onCleared() } - fun create() { + override fun onFlexiApiTokenReceived() { + Log.i("[Phone Account Creation] Using FlexiAPI auth token [${accountCreator.token}]") accountCreator.displayName = displayName.value accountCreator.setPhoneNumber(phoneNumber.value, prefix.value) + if (useUsername.value == true) { accountCreator.username = username.value } else { accountCreator.username = accountCreator.phoneNumber } - waitForServerAnswer.value = true + if (useUsername.value == true) { + checkUsername() + } else { + checkPhoneNumber() + } + } + + override fun onFlexiApiTokenRequestError() { + Log.e("[Phone Account Creation] Failed to get an auth token from FlexiAPI") + waitForServerAnswer.value = false + onErrorEvent.value = Event("Error: Failed to get an auth token from account manager server") + } + + private fun checkUsername() { val status = accountCreator.isAccountExist Log.i("[Phone Account Creation] isAccountExist returned $status") if (status != AccountCreator.Status.RequestOk) { @@ -168,6 +213,29 @@ class PhoneAccountCreationViewModel(accountCreator: AccountCreator) : AbstractPh } } + private fun checkPhoneNumber() { + val status = accountCreator.isAliasUsed + Log.i("[Phone Account Creation] isAliasUsed returned $status") + if (status != AccountCreator.Status.RequestOk) { + waitForServerAnswer.value = false + onErrorEvent.value = Event("Error: ${status.name}") + } + } + + fun create() { + val token = accountCreator.token.orEmpty() + if (token.isNotEmpty()) { + Log.i( + "[Phone Account Creation] We already have an auth token from FlexiAPI [$token], continue" + ) + onFlexiApiTokenReceived() + } else { + Log.i("[Phone Account Creation] Requesting an auth token from FlexiAPI") + waitForServerAnswer.value = true + requestFlexiApiToken() + } + } + private fun isCreateButtonEnabled(): Boolean { val usernameRegexp = corePreferences.config.getString( "assistant", diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountLinkingViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountLinkingViewModel.kt index 62c8bf9e5..b38b8e86d 100644 --- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountLinkingViewModel.kt +++ b/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountLinkingViewModel.kt @@ -120,12 +120,11 @@ class PhoneAccountLinkingViewModel(accountCreator: AccountCreator) : AbstractPho super.onCleared() } - fun link() { + override fun onFlexiApiTokenReceived() { accountCreator.setPhoneNumber(phoneNumber.value, prefix.value) accountCreator.username = username.value - Log.i("[Assistant] [Phone Account Linking] Phone number is ${accountCreator.phoneNumber}") + Log.i("[Phone Account Linking] Phone number is ${accountCreator.phoneNumber}") - waitForServerAnswer.value = true val status: AccountCreator.Status = accountCreator.isAliasUsed Log.i("[Phone Account Linking] isAliasUsed returned $status") if (status != AccountCreator.Status.RequestOk) { @@ -134,6 +133,17 @@ class PhoneAccountLinkingViewModel(accountCreator: AccountCreator) : AbstractPho } } + override fun onFlexiApiTokenRequestError() { + Log.e("[Phone Account Linking] Failed to get an auth token from FlexiAPI") + waitForServerAnswer.value = false + } + + fun link() { + Log.i("[Phone Account Linking] Requesting an auth token from FlexiAPI") + waitForServerAnswer.value = true + requestFlexiApiToken() + } + fun skip() { leaveAssistantEvent.value = Event(true) } diff --git a/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountValidationViewModel.kt b/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountValidationViewModel.kt index 5b6592341..cf1f3f787 100644 --- a/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountValidationViewModel.kt +++ b/app/src/main/java/org/linphone/activities/assistant/viewmodels/PhoneAccountValidationViewModel.kt @@ -24,7 +24,6 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import org.linphone.core.AccountCreator import org.linphone.core.AccountCreatorListenerStub -import org.linphone.core.ProxyConfig import org.linphone.core.tools.Log import org.linphone.utils.Event @@ -66,7 +65,7 @@ class PhoneAccountValidationViewModel(val accountCreator: AccountCreator) : View waitForServerAnswer.value = false if (status == AccountCreator.Status.RequestOk) { - if (createProxyConfig()) { + if (createAccountAndAuthInfo()) { leaveAssistantEvent.value = Event(true) } else { onErrorEvent.value = Event("Error: Failed to create account object") @@ -103,7 +102,7 @@ class PhoneAccountValidationViewModel(val accountCreator: AccountCreator) : View waitForServerAnswer.value = false if (status == AccountCreator.Status.AccountActivated) { - if (createProxyConfig()) { + if (createAccountAndAuthInfo()) { leaveAssistantEvent.value = Event(true) } else { onErrorEvent.value = Event("Error: Failed to create account object") @@ -143,18 +142,21 @@ class PhoneAccountValidationViewModel(val accountCreator: AccountCreator) : View } } - private fun createProxyConfig(): Boolean { - val proxyConfig: ProxyConfig? = accountCreator.createProxyConfig() + private fun createAccountAndAuthInfo(): Boolean { + val account = accountCreator.createAccountInCore() - if (proxyConfig == null) { + if (account == null) { Log.e( - "[Assistant] [Phone Account Validation] Account creator couldn't create proxy config" + "[Assistant] [Phone Account Validation] Account creator couldn't create account" ) return false } - proxyConfig.isPushNotificationAllowed = true - Log.i("[Assistant] [Phone Account Validation] Proxy config created") + val params = account.params.clone() + params.pushNotificationAllowed = true + account.params = params + + Log.i("[Assistant] [Phone Account Validation] Account created") return true } } diff --git a/app/src/main/java/org/linphone/activities/main/chat/fragments/ChatRoomCreationFragment.kt b/app/src/main/java/org/linphone/activities/main/chat/fragments/ChatRoomCreationFragment.kt index 52225b074..59c45515b 100644 --- a/app/src/main/java/org/linphone/activities/main/chat/fragments/ChatRoomCreationFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/chat/fragments/ChatRoomCreationFragment.kt @@ -27,6 +27,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.R +import org.linphone.activities.GenericActivity import org.linphone.activities.main.MainActivity import org.linphone.activities.main.chat.viewmodels.ChatRoomCreationViewModel import org.linphone.activities.main.fragments.SecureFragment @@ -74,7 +75,7 @@ class ChatRoomCreationFragment : SecureFragment AppUtils.getDividerDecoration(requireContext(), layoutManager) ) - binding.back.visibility = if (resources.getBoolean(R.bool.isTablet)) View.INVISIBLE else View.VISIBLE + binding.back.visibility = if ((requireActivity() as GenericActivity).isTablet()) View.INVISIBLE else View.VISIBLE binding.setAllContactsToggleClickListener { viewModel.sipContactsSelected.value = false diff --git a/app/src/main/java/org/linphone/activities/main/dialer/fragments/DialerFragment.kt b/app/src/main/java/org/linphone/activities/main/dialer/fragments/DialerFragment.kt index e917fa9bd..b59729e39 100644 --- a/app/src/main/java/org/linphone/activities/main/dialer/fragments/DialerFragment.kt +++ b/app/src/main/java/org/linphone/activities/main/dialer/fragments/DialerFragment.kt @@ -38,6 +38,7 @@ import org.linphone.BuildConfig import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.corePreferences import org.linphone.R +import org.linphone.activities.GenericActivity import org.linphone.activities.main.MainActivity import org.linphone.activities.main.dialer.viewmodels.DialerViewModel import org.linphone.activities.main.fragments.SecureFragment @@ -213,7 +214,7 @@ class DialerFragment : SecureFragment() { override fun onResume() { super.onResume() - if (resources.getBoolean(R.bool.isTablet)) { + if ((requireActivity() as GenericActivity).isTablet()) { coreContext.core.nativePreviewWindowId = binding.videoPreviewWindow } diff --git a/app/src/main/java/org/linphone/activities/main/settings/viewmodels/AccountSettingsViewModel.kt b/app/src/main/java/org/linphone/activities/main/settings/viewmodels/AccountSettingsViewModel.kt index f9febad28..6cfb7713d 100644 --- a/app/src/main/java/org/linphone/activities/main/settings/viewmodels/AccountSettingsViewModel.kt +++ b/app/src/main/java/org/linphone/activities/main/settings/viewmodels/AccountSettingsViewModel.kt @@ -31,6 +31,7 @@ import org.linphone.activities.main.settings.SettingListenerStub import org.linphone.core.* import org.linphone.core.tools.Log import org.linphone.utils.Event +import org.linphone.utils.LinphoneUtils class AccountSettingsViewModelFactory(private val identity: String) : ViewModelProvider.NewInstanceFactory() { @@ -408,7 +409,7 @@ class AccountSettingsViewModel(val account: Account) : GenericSettingsViewModel( override fun onTextValueChanged(newValue: String) { val params = account.params.clone() Log.i( - "[Account Settings] Forcing conference factory on proxy config ${params.identityAddress?.asString()} to value: $newValue" + "[Account Settings] Forcing conference factory on account ${params.identityAddress?.asString()} to value: $newValue" ) params.conferenceFactoryUri = newValue account.params = params @@ -421,7 +422,7 @@ class AccountSettingsViewModel(val account: Account) : GenericSettingsViewModel( val params = account.params.clone() val uri = coreContext.core.interpretUrl(newValue, false) Log.i( - "[Account Settings] Forcing audio/video conference factory on proxy config ${params.identityAddress?.asString()} to value: $newValue" + "[Account Settings] Forcing audio/video conference factory on account ${params.identityAddress?.asString()} to value: $newValue" ) params.audioVideoConferenceFactoryAddress = uri account.params = params @@ -500,7 +501,7 @@ class AccountSettingsViewModel(val account: Account) : GenericSettingsViewModel( domain.value = params.identityAddress?.domain disable.value = !params.isRegisterEnabled pushNotification.value = params.pushNotificationAllowed - pushNotificationsAvailable.value = core.isPushNotificationAvailable + pushNotificationsAvailable.value = LinphoneUtils.isPushNotificationAvailable() proxy.value = params.serverAddress?.asStringUriOnly() outboundProxy.value = params.isOutboundProxyEnabled stunServer.value = params.natPolicy?.stunServer diff --git a/app/src/main/java/org/linphone/core/CoreContext.kt b/app/src/main/java/org/linphone/core/CoreContext.kt index 12432dccd..22c11d43d 100644 --- a/app/src/main/java/org/linphone/core/CoreContext.kt +++ b/app/src/main/java/org/linphone/core/CoreContext.kt @@ -501,7 +501,7 @@ class CoreContext( val newExpire = 2629800 // 1 month if (account.params.expires != newExpire) { Log.i( - "[Context] Updating expire on proxy config ${params.identityAddress?.asString()} from ${account.params.expires} to newExpire" + "[Context] Updating expire on account ${params.identityAddress?.asString()} from ${account.params.expires} to newExpire" ) params.expires = newExpire paramsChanged = true @@ -510,7 +510,7 @@ class CoreContext( // Enable presence publish/subscribe for new feature if (!account.params.isPublishEnabled) { Log.i( - "[Context] Enabling presence publish on proxy config ${params.identityAddress?.asString()}" + "[Context] Enabling presence publish on account ${params.identityAddress?.asString()}" ) params.isPublishEnabled = true params.publishExpires = 120 @@ -518,23 +518,23 @@ class CoreContext( } } - // Ensure conference factory URI is set on sip.linphone.org proxy configs + // Ensure conference factory URI is set on sip.linphone.org accounts if (account.params.conferenceFactoryUri == null) { val uri = corePreferences.conferenceServerUri Log.i( - "[Context] Setting conference factory on proxy config ${params.identityAddress?.asString()} to default value: $uri" + "[Context] Setting conference factory on account ${params.identityAddress?.asString()} to default value: $uri" ) params.conferenceFactoryUri = uri paramsChanged = true } - // Ensure audio/video conference factory URI is set on sip.linphone.org proxy configs + // Ensure audio/video conference factory URI is set on sip.linphone.org accounts if (account.params.audioVideoConferenceFactoryAddress == null) { val uri = corePreferences.audioVideoConferenceServerUri val address = core.interpretUrl(uri, false) if (address != null) { Log.i( - "[Context] Setting audio/video conference factory on proxy config ${params.identityAddress?.asString()} to default value: $uri" + "[Context] Setting audio/video conference factory on account ${params.identityAddress?.asString()} to default value: $uri" ) params.audioVideoConferenceFactoryAddress = address paramsChanged = true @@ -546,7 +546,7 @@ class CoreContext( // Enable Bundle mode by default if (!account.params.isRtpBundleEnabled) { Log.i( - "[Context] Enabling RTP bundle mode on proxy config ${params.identityAddress?.asString()}" + "[Context] Enabling RTP bundle mode on account ${params.identityAddress?.asString()}" ) params.isRtpBundleEnabled = true paramsChanged = true diff --git a/app/src/main/java/org/linphone/utils/LinphoneUtils.kt b/app/src/main/java/org/linphone/utils/LinphoneUtils.kt index e386dc3c0..1d4f47857 100644 --- a/app/src/main/java/org/linphone/utils/LinphoneUtils.kt +++ b/app/src/main/java/org/linphone/utils/LinphoneUtils.kt @@ -274,6 +274,20 @@ class LinphoneUtils { return true // Legacy behavior } + fun isPushNotificationAvailable(): Boolean { + val core = coreContext.core + if (!core.isPushNotificationAvailable) { + return false + } + + val pushConfig = core.pushNotificationConfig ?: return false + if (pushConfig.provider.isNullOrEmpty()) return false + if (pushConfig.param.isNullOrEmpty()) return false + if (pushConfig.prid.isNullOrEmpty()) return false + + return true + } + fun hashPassword( userId: String, password: String, diff --git a/app/src/main/res/layout/assistant_account_login_fragment.xml b/app/src/main/res/layout/assistant_account_login_fragment.xml index 0581f29a7..f1b69fd8f 100644 --- a/app/src/main/res/layout/assistant_account_login_fragment.xml +++ b/app/src/main/res/layout/assistant_account_login_fragment.xml @@ -84,9 +84,9 @@ android:onClick="@{infoClickListener}" android:contentDescription="@string/content_description_phone_number_use" android:src="@drawable/info" - android:layout_marginTop="10dp" - android:layout_below="@id/phone_number_desc" - android:layout_alignParentRight="true" + android:layout_alignParentEnd="true" + android:layout_alignTop="@id/select_country_label" + android:layout_above="@id/select_country" android:layout_width="20dp" android:layout_height="20dp"/> @@ -222,7 +222,8 @@ android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="center" - android:paddingTop="10dp"> + android:paddingTop="10dp" + android:visibility="@{viewModel.forceLoginUsingUsernameAndPassword ? View.GONE : View.VISIBLE}"> + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/assistant_phone_account_creation_fragment.xml b/app/src/main/res/layout/assistant_phone_account_creation_fragment.xml index 0250c7eb1..63a68b65d 100644 --- a/app/src/main/res/layout/assistant_phone_account_creation_fragment.xml +++ b/app/src/main/res/layout/assistant_phone_account_creation_fragment.xml @@ -44,7 +44,7 @@ android:layout_height="wrap_content" android:gravity="center" android:text="@string/assistant_create_account" - android:paddingTop="10dp" + android:layout_marginTop="10dp" android:textAllCaps="true" /> @@ -92,7 +94,7 @@ android:padding="10dp" android:layout_marginTop="5dp" android:gravity="center" - android:layout_below="@id/phone_number_label"/> + android:layout_below="@id/select_country_label"/> + + + + + + diff --git a/app/src/main/res/layout/assistant_phone_account_linking_fragment.xml b/app/src/main/res/layout/assistant_phone_account_linking_fragment.xml index b17358407..b114f93a4 100644 --- a/app/src/main/res/layout/assistant_phone_account_linking_fragment.xml +++ b/app/src/main/res/layout/assistant_phone_account_linking_fragment.xml @@ -80,8 +80,8 @@ android:layout_height="wrap_content"> @@ -107,7 +109,7 @@ android:padding="10dp" android:layout_marginTop="5dp" android:gravity="center" - android:layout_below="@id/phone_number_label"/> + android:layout_below="@id/select_country_label"/> + + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index af31bf418..4ca897fd9 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -176,7 +176,7 @@ Vous ne pouvez associer votre numéro qu\'à un seul compte &appName;.\n\nSi vous avez déjà associé votre numéro à un autre compte mais préférez utiliser ce compte-ci, suivez la procédure d\'association et votre numéro sera automatiquement transféré à ce compte. Entrez uniquement des chiffres Ce nom d\'utilisateur est déjà utilisé - Ce nom d\'utilisateur est déjà pris + Ce numéro de téléphone est déjà utilisé Caractères invalides Les mots de passe ne correspondent pas L\'adresse email est invalide @@ -782,4 +782,7 @@ Le mot de passe est invalide ! Désactiver le mode bundle + Pour créer un compte avec votre email : + Votre périphérique ne semble pas supporter les notifications \'push\'.\n\nVous ne pourrez donc pas créer des comptes dans l\'application mais vous pouvez toujours le faire sur notre site internet : + Votre compte n\'est pas activé, veuillez cliquer sur le lien que vous avez reçu par courriel \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bb98d3699..cc6f60741 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -410,6 +410,8 @@ Some features require a &appName; account, such as group messaging or ephemeral messaging.\n\nThese features are hidden when you register with a third party SIP account.\n\nTo enable it in a commercial project, please contact us. https://www.linphone.org/contact I understand + To create an account using your email: + Your device doesn\'t seem to be able to receive push notifications.\n\nAs we now require them for the account creation process, you won\'t be able to create an account inside the app, but you can create it on our website: Only digits are expected here @@ -424,7 +426,7 @@ Use your &appName; account Please confirm your country code and enter your phone number - Please enter your username and password of &appName; account + Please enter your &appName; account username and password Use your username and password instead of your phone number Forgot your password? https://subscribe.linphone.org/ @@ -448,6 +450,7 @@ To complete your phone number verification, please enter the 4 digit code below:\n You will link with your phone number the following username: Skip + Your account has not been activated yet, please click on the link you received by email Link account @@ -575,7 +578,7 @@ Create shortcuts to chat rooms in launcher Will be replaced by contacts shortcuts if enabled Hide empty chat rooms - Hide chat rooms from removed proxy configs + Hide chat rooms from removed accounts If you are missing chat rooms, try to uncheck this setting Android notification settings Always open files inside this app @@ -691,7 +694,7 @@ Delete Advanced Allow push notification - Proxy config won\'t unregister + Account won\'t unregister Transport UDP TCP