mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-05-03 15:26:27 +00:00
Added auth requested dialog
This commit is contained in:
parent
8750c2da55
commit
a707c6c988
6 changed files with 277 additions and 0 deletions
|
|
@ -55,9 +55,11 @@ import org.linphone.databinding.MainActivityBinding
|
||||||
import org.linphone.ui.GenericActivity
|
import org.linphone.ui.GenericActivity
|
||||||
import org.linphone.ui.assistant.AssistantActivity
|
import org.linphone.ui.assistant.AssistantActivity
|
||||||
import org.linphone.ui.main.chat.fragment.ConversationsListFragmentDirections
|
import org.linphone.ui.main.chat.fragment.ConversationsListFragmentDirections
|
||||||
|
import org.linphone.ui.main.fragment.AuthRequestedDialogModel
|
||||||
import org.linphone.ui.main.viewmodel.MainViewModel
|
import org.linphone.ui.main.viewmodel.MainViewModel
|
||||||
import org.linphone.ui.main.viewmodel.SharedMainViewModel
|
import org.linphone.ui.main.viewmodel.SharedMainViewModel
|
||||||
import org.linphone.ui.welcome.WelcomeActivity
|
import org.linphone.ui.welcome.WelcomeActivity
|
||||||
|
import org.linphone.utils.DialogUtils
|
||||||
import org.linphone.utils.Event
|
import org.linphone.utils.Event
|
||||||
import org.linphone.utils.FileUtils
|
import org.linphone.utils.FileUtils
|
||||||
import org.linphone.utils.LinphoneUtils
|
import org.linphone.utils.LinphoneUtils
|
||||||
|
|
@ -164,6 +166,12 @@ class MainActivity : GenericActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModel.authenticationRequestedEvent.observe(this) {
|
||||||
|
it.consume { identity ->
|
||||||
|
showAuthenticationRequestedDialog(identity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.root.doOnAttach {
|
binding.root.doOnAttach {
|
||||||
Log.i("$TAG Report UI has been fully drawn (TTFD)")
|
Log.i("$TAG Report UI has been fully drawn (TTFD)")
|
||||||
try {
|
try {
|
||||||
|
|
@ -615,4 +623,24 @@ class MainActivity : GenericActivity() {
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showAuthenticationRequestedDialog(identity: String) {
|
||||||
|
val model = AuthRequestedDialogModel(identity)
|
||||||
|
val dialog = DialogUtils.getAuthRequestedDialog(this, model)
|
||||||
|
|
||||||
|
model.dismissEvent.observe(this) {
|
||||||
|
it.consume {
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
model.confirmEvent.observe(this) {
|
||||||
|
it.consume { password ->
|
||||||
|
viewModel.updateAuthInfo(password)
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* 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.ui.main.fragment
|
||||||
|
|
||||||
|
import androidx.annotation.UiThread
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import org.linphone.R
|
||||||
|
import org.linphone.utils.AppUtils
|
||||||
|
import org.linphone.utils.Event
|
||||||
|
|
||||||
|
class AuthRequestedDialogModel @UiThread constructor(identity: String) {
|
||||||
|
val message = MutableLiveData<String>()
|
||||||
|
|
||||||
|
val password = MutableLiveData<String>()
|
||||||
|
|
||||||
|
val dismissEvent = MutableLiveData<Event<Boolean>>()
|
||||||
|
|
||||||
|
val confirmEvent = MutableLiveData<Event<String>>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
message.value = AppUtils.getFormattedString(
|
||||||
|
R.string.dialog_account_invalid_password_message,
|
||||||
|
identity
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
fun dismiss() {
|
||||||
|
dismissEvent.value = Event(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
fun confirm() {
|
||||||
|
confirmEvent.value = Event(password.value.orEmpty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -33,6 +33,8 @@ import kotlinx.coroutines.withContext
|
||||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||||
import org.linphone.R
|
import org.linphone.R
|
||||||
import org.linphone.core.Account
|
import org.linphone.core.Account
|
||||||
|
import org.linphone.core.AuthInfo
|
||||||
|
import org.linphone.core.AuthMethod
|
||||||
import org.linphone.core.Call
|
import org.linphone.core.Call
|
||||||
import org.linphone.core.Core
|
import org.linphone.core.Core
|
||||||
import org.linphone.core.CoreListenerStub
|
import org.linphone.core.CoreListenerStub
|
||||||
|
|
@ -88,6 +90,10 @@ class MainViewModel @UiThread constructor() : ViewModel() {
|
||||||
MutableLiveData<Event<Boolean>>()
|
MutableLiveData<Event<Boolean>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val authenticationRequestedEvent: MutableLiveData<Event<String>> by lazy {
|
||||||
|
MutableLiveData<Event<String>>()
|
||||||
|
}
|
||||||
|
|
||||||
var accountsFound = -1
|
var accountsFound = -1
|
||||||
|
|
||||||
var mainIntentHandled = false
|
var mainIntentHandled = false
|
||||||
|
|
@ -100,6 +106,8 @@ class MainViewModel @UiThread constructor() : ViewModel() {
|
||||||
|
|
||||||
private var firstAccountRegistered: Boolean = false
|
private var firstAccountRegistered: Boolean = false
|
||||||
|
|
||||||
|
private var authInfoPendingPasswordUpdate: AuthInfo? = null
|
||||||
|
|
||||||
private val coreListener = object : CoreListenerStub() {
|
private val coreListener = object : CoreListenerStub() {
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
override fun onLastCallEnded(core: Core) {
|
override fun onLastCallEnded(core: Core) {
|
||||||
|
|
@ -108,6 +116,7 @@ class MainViewModel @UiThread constructor() : ViewModel() {
|
||||||
atLeastOneCall.postValue(false)
|
atLeastOneCall.postValue(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
override fun onFirstCallStarted(core: Core) {
|
override fun onFirstCallStarted(core: Core) {
|
||||||
Log.i("$TAG First call started, adding in-call 'alert'")
|
Log.i("$TAG First call started, adding in-call 'alert'")
|
||||||
updateCallAlert()
|
updateCallAlert()
|
||||||
|
|
@ -225,6 +234,7 @@ class MainViewModel @UiThread constructor() : ViewModel() {
|
||||||
// TODO: compute other calls notifications count
|
// TODO: compute other calls notifications count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
override fun onAccountRemoved(core: Core, account: Account) {
|
override fun onAccountRemoved(core: Core, account: Account) {
|
||||||
accountsFound -= 1
|
accountsFound -= 1
|
||||||
|
|
||||||
|
|
@ -235,6 +245,27 @@ class MainViewModel @UiThread constructor() : ViewModel() {
|
||||||
core.defaultAccount = core.accountList.firstOrNull()
|
core.defaultAccount = core.accountList.firstOrNull()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
override fun onAuthenticationRequested(core: Core, authInfo: AuthInfo, method: AuthMethod) {
|
||||||
|
if (authInfo.username == null || authInfo.domain == null || authInfo.realm == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.w(
|
||||||
|
"$TAG Authentication requested for account [${authInfo.username}@${authInfo.domain}] with realm [${authInfo.realm}] using method [$method]"
|
||||||
|
)
|
||||||
|
val accountFound = core.accountList.find {
|
||||||
|
it.params.identityAddress?.username == authInfo.username && it.params.identityAddress?.domain == authInfo.domain
|
||||||
|
}
|
||||||
|
if (accountFound == null) {
|
||||||
|
Log.w("$TAG Failed to find account matching auth info, aborting auth dialog")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val identity = "${authInfo.username}@${authInfo.domain}"
|
||||||
|
authInfoPendingPasswordUpdate = authInfo
|
||||||
|
authenticationRequestedEvent.postValue(Event(identity))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
@ -308,6 +339,22 @@ class MainViewModel @UiThread constructor() : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
fun updateAuthInfo(password: String) {
|
||||||
|
coreContext.postOnCoreThread { core ->
|
||||||
|
val authInfo = authInfoPendingPasswordUpdate
|
||||||
|
if (authInfo != null) {
|
||||||
|
Log.i(
|
||||||
|
"$TAG Updating password for username [${authInfo.username}] using auth info [$authInfo]"
|
||||||
|
)
|
||||||
|
authInfo.password = password
|
||||||
|
core.addAuthInfo(authInfo)
|
||||||
|
authInfoPendingPasswordUpdate = null
|
||||||
|
core.refreshRegisters()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
private fun updateCallAlert() {
|
private fun updateCallAlert() {
|
||||||
val core = coreContext.core
|
val core = coreContext.core
|
||||||
|
|
|
||||||
|
|
@ -45,12 +45,14 @@ import org.linphone.databinding.DialogRemoveAccountBinding
|
||||||
import org.linphone.databinding.DialogRemoveAllCallLogsBinding
|
import org.linphone.databinding.DialogRemoveAllCallLogsBinding
|
||||||
import org.linphone.databinding.DialogRemoveCallLogsBinding
|
import org.linphone.databinding.DialogRemoveCallLogsBinding
|
||||||
import org.linphone.databinding.DialogSetOrEditGroupSubjectBindingImpl
|
import org.linphone.databinding.DialogSetOrEditGroupSubjectBindingImpl
|
||||||
|
import org.linphone.databinding.DialogUpdateAccountPasswordBinding
|
||||||
import org.linphone.databinding.DialogUpdateAvailableBinding
|
import org.linphone.databinding.DialogUpdateAvailableBinding
|
||||||
import org.linphone.ui.assistant.model.AcceptConditionsAndPolicyDialogModel
|
import org.linphone.ui.assistant.model.AcceptConditionsAndPolicyDialogModel
|
||||||
import org.linphone.ui.assistant.model.ConfirmPhoneNumberDialogModel
|
import org.linphone.ui.assistant.model.ConfirmPhoneNumberDialogModel
|
||||||
import org.linphone.ui.call.model.ZrtpSasConfirmationDialogModel
|
import org.linphone.ui.call.model.ZrtpSasConfirmationDialogModel
|
||||||
import org.linphone.ui.main.contacts.model.NumberOrAddressPickerDialogModel
|
import org.linphone.ui.main.contacts.model.NumberOrAddressPickerDialogModel
|
||||||
import org.linphone.ui.main.contacts.model.TrustCallDialogModel
|
import org.linphone.ui.main.contacts.model.TrustCallDialogModel
|
||||||
|
import org.linphone.ui.main.fragment.AuthRequestedDialogModel
|
||||||
import org.linphone.ui.main.fragment.GroupSetOrEditSubjectDialogModel
|
import org.linphone.ui.main.fragment.GroupSetOrEditSubjectDialogModel
|
||||||
import org.linphone.ui.main.history.model.ConfirmationDialogModel
|
import org.linphone.ui.main.history.model.ConfirmationDialogModel
|
||||||
|
|
||||||
|
|
@ -301,6 +303,22 @@ class DialogUtils {
|
||||||
return getDialog(context, binding)
|
return getDialog(context, binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
|
fun getAuthRequestedDialog(
|
||||||
|
context: Context,
|
||||||
|
viewModel: AuthRequestedDialogModel
|
||||||
|
): Dialog {
|
||||||
|
val binding: DialogUpdateAccountPasswordBinding = DataBindingUtil.inflate(
|
||||||
|
LayoutInflater.from(context),
|
||||||
|
R.layout.dialog_update_account_password,
|
||||||
|
null,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
return getDialog(context, binding)
|
||||||
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
fun getZrtpSasConfirmationDialog(
|
fun getZrtpSasConfirmationDialog(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
|
|
||||||
128
app/src/main/res/layout/dialog_update_account_password.xml
Normal file
128
app/src/main/res/layout/dialog_update_account_password.xml
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
<import type="android.view.View" />
|
||||||
|
<import type="android.graphics.Typeface" />
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="org.linphone.ui.main.fragment.AuthRequestedDialogModel" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:onClick="@{() -> viewModel.dismiss()}"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/dialog_background"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:layout_marginBottom="2dp"
|
||||||
|
android:src="@drawable/shape_dialog_background"
|
||||||
|
app:layout_constraintWidth_max="@dimen/dialog_max_width"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/anchor"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/title" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
style="@style/section_header_style"
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="15dp"
|
||||||
|
android:paddingTop="@dimen/dialog_top_bottom_margin"
|
||||||
|
android:text="@string/dialog_account_invalid_password_title"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/message"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/dialog_background"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/dialog_background"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
style="@style/default_text_style_500"
|
||||||
|
android:id="@+id/message"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="@{viewModel.message, default=@string/dialog_account_invalid_password_message}"
|
||||||
|
android:textAlignment="center"
|
||||||
|
app:layout_constraintWidth_max="@dimen/text_input_max_width"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/password"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/dialog_background"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/dialog_background"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/title" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatEditText
|
||||||
|
style="@style/default_text_style"
|
||||||
|
android:id="@+id/password"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:paddingStart="20dp"
|
||||||
|
android:paddingEnd="20dp"
|
||||||
|
android:hint="@string/dialog_account_invalid_password_hint"
|
||||||
|
android:text="@={viewModel.password}"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="?attr/color_main2_600"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:background="@drawable/edit_text_background"
|
||||||
|
android:inputType="text|textCapSentences"
|
||||||
|
app:layout_constraintHorizontal_bias="0"
|
||||||
|
app:layout_constraintWidth_max="@dimen/text_input_max_width"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/cancel"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/dialog_background"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/dialog_background"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/message"/>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:onClick="@{() -> viewModel.dismiss()}"
|
||||||
|
style="@style/secondary_button_label_style"
|
||||||
|
android:id="@+id/cancel"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
android:layout_marginStart="15dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:text="@string/dialog_cancel"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/dialog_background"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/dialog_background"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/password"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/confirm"/>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:onClick="@{() -> viewModel.confirm()}"
|
||||||
|
style="@style/primary_button_label_style"
|
||||||
|
android:id="@+id/confirm"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginStart="15dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:text="@string/dialog_group_conversation_edit_subject_confirm_button"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/dialog_background"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/dialog_background"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/cancel"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/anchor"/>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/anchor"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="@dimen/dialog_top_bottom_margin"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/confirm"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/dialog_background"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/dialog_background"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</layout>
|
||||||
|
|
@ -127,6 +127,9 @@
|
||||||
<string name="dialog_group_conversation_edit_subject_confirm_button">Confirm</string>
|
<string name="dialog_group_conversation_edit_subject_confirm_button">Confirm</string>
|
||||||
<string name="dialog_group_call_set_subject">Set group call subject</string>
|
<string name="dialog_group_call_set_subject">Set group call subject</string>
|
||||||
<string name="dialog_group_call_subject_hint">Group call subject</string>
|
<string name="dialog_group_call_subject_hint">Group call subject</string>
|
||||||
|
<string name="dialog_account_invalid_password_title">Authentication needed</string>
|
||||||
|
<string name="dialog_account_invalid_password_message">Connection failed because authentication is missing or invalid for account \n%s.\n\nYou can provide password again, or check your account configuration in the settings.</string>
|
||||||
|
<string name="dialog_account_invalid_password_hint">New password</string>
|
||||||
|
|
||||||
<string name="toast_assistant_qr_code_invalid">Invalid QR code!</string>
|
<string name="toast_assistant_qr_code_invalid">Invalid QR code!</string>
|
||||||
<string name="toast_sip_address_copied_to_clipboard">SIP address copied into clipboard</string>
|
<string name="toast_sip_address_copied_to_clipboard">SIP address copied into clipboard</string>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue