Cherry pick previous commits.

This commit is contained in:
Onuray Sahin 2022-10-13 20:33:52 +03:00
parent d8ea9c8215
commit fb2776dca4
16 changed files with 121 additions and 13 deletions

View file

@ -124,4 +124,10 @@ interface AuthenticationService {
initialDeviceName: String,
deviceId: String? = null
): Session
/**
* @param homeServerConnectionConfig the information about the homeserver and other configuration
* Return true if qr code login is supported by the server, false otherwise.
*/
suspend fun isQrLoginSupported(homeServerConnectionConfig: HomeServerConnectionConfig): Boolean
}

View file

@ -59,7 +59,12 @@ data class HomeServerCapabilities(
/**
* True if the home server supports controlling the logout of all devices when changing password.
*/
val canControlLogoutDevices: Boolean = false
val canControlLogoutDevices: Boolean = false,
/**
* True if the home server supports login via qr code, false otherwise.
*/
val canLoginWithQrCode: Boolean = false,
) {
enum class RoomCapabilitySupport {

View file

@ -30,6 +30,7 @@ import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
import org.matrix.android.sdk.api.auth.login.LoginWizard
import org.matrix.android.sdk.api.auth.registration.RegistrationWizard
import org.matrix.android.sdk.api.auth.wellknown.WellknownResult
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.failure.Failure
import org.matrix.android.sdk.api.failure.MatrixIdFailure
import org.matrix.android.sdk.api.session.Session
@ -42,6 +43,7 @@ import org.matrix.android.sdk.internal.auth.login.DirectLoginTask
import org.matrix.android.sdk.internal.auth.registration.DefaultRegistrationWizard
import org.matrix.android.sdk.internal.auth.version.Versions
import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices
import org.matrix.android.sdk.internal.auth.version.doesServerSupportQrCodeLogin
import org.matrix.android.sdk.internal.auth.version.isLoginAndRegistrationSupportedBySdk
import org.matrix.android.sdk.internal.auth.version.isSupportedBySdk
import org.matrix.android.sdk.internal.di.Unauthenticated
@ -404,6 +406,20 @@ internal class DefaultAuthenticationService @Inject constructor(
)
}
override suspend fun isQrLoginSupported(homeServerConnectionConfig: HomeServerConnectionConfig): Boolean {
val authAPI = buildAuthAPI(homeServerConnectionConfig)
val versions = runCatching {
executeRequest(null) {
authAPI.versions()
}
}
return if (versions.isSuccess) {
versions.getOrNull()?.doesServerSupportQrCodeLogin().orFalse()
} else {
false
}
}
private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI {
val retrofit = retrofitFactory.create(buildClient(homeServerConnectionConfig), homeServerConnectionConfig.homeServerUriBase.toString())
return retrofit.create(AuthAPI::class.java)

View file

@ -53,6 +53,7 @@ private const val FEATURE_ID_ACCESS_TOKEN = "m.id_access_token"
private const val FEATURE_SEPARATE_ADD_AND_BIND = "m.separate_add_and_bind"
private const val FEATURE_THREADS_MSC3440 = "org.matrix.msc3440"
private const val FEATURE_THREADS_MSC3440_STABLE = "org.matrix.msc3440.stable"
private const val FEATURE_QR_CODE_LOGIN = "org.matrix.msc3882"
/**
* Return true if the SDK supports this homeserver version.
@ -78,6 +79,10 @@ internal fun Versions.doesServerSupportThreads(): Boolean {
return unstableFeatures?.get(FEATURE_THREADS_MSC3440_STABLE) ?: false
}
internal fun Versions.doesServerSupportQrCodeLogin(): Boolean {
return unstableFeatures?.get(FEATURE_QR_CODE_LOGIN) ?: false
}
/**
* Return true if the server support the lazy loading of room members.
*

View file

@ -54,6 +54,7 @@ import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo034
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo035
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo036
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo037
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo038
import org.matrix.android.sdk.internal.util.Normalizer
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
import javax.inject.Inject
@ -62,7 +63,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
private val normalizer: Normalizer
) : MatrixRealmMigration(
dbName = "Session",
schemaVersion = 37L,
schemaVersion = 38L,
) {
/**
* Forces all RealmSessionStoreMigration instances to be equal.
@ -109,5 +110,6 @@ internal class RealmSessionStoreMigration @Inject constructor(
if (oldVersion < 35) MigrateSessionTo035(realm).perform()
if (oldVersion < 36) MigrateSessionTo036(realm).perform()
if (oldVersion < 37) MigrateSessionTo037(realm).perform()
if (oldVersion < 38) MigrateSessionTo038(realm).perform()
}
}

View file

@ -43,7 +43,8 @@ internal object HomeServerCapabilitiesMapper {
defaultIdentityServerUrl = entity.defaultIdentityServerUrl,
roomVersions = mapRoomVersion(entity.roomVersionsJson),
canUseThreading = entity.canUseThreading,
canControlLogoutDevices = entity.canControlLogoutDevices
canControlLogoutDevices = entity.canControlLogoutDevices,
canLoginWithQrCode = entity.canLoginWithQrCode,
)
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.database.migration
import io.realm.DynamicRealm
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
import org.matrix.android.sdk.internal.extensions.forceRefreshOfHomeServerCapabilities
import org.matrix.android.sdk.internal.util.database.RealmMigrator
internal class MigrateSessionTo038(realm: DynamicRealm) : RealmMigrator(realm, 38) {
override fun doMigrate(realm: DynamicRealm) {
realm.schema.get("HomeServerCapabilitiesEntity")
?.addField(HomeServerCapabilitiesEntityFields.CAN_LOGIN_WITH_QR_CODE, Boolean::class.java)
?.transform { obj ->
obj.set(HomeServerCapabilitiesEntityFields.CAN_LOGIN_WITH_QR_CODE, false)
}
?.forceRefreshOfHomeServerCapabilities()
}
}

View file

@ -30,7 +30,8 @@ internal open class HomeServerCapabilitiesEntity(
var defaultIdentityServerUrl: String? = null,
var lastUpdatedTimestamp: Long = 0L,
var canUseThreading: Boolean = false,
var canControlLogoutDevices: Boolean = false
var canControlLogoutDevices: Boolean = false,
var canLoginWithQrCode: Boolean = false,
) : RealmObject() {
companion object

View file

@ -25,6 +25,7 @@ import org.matrix.android.sdk.api.extensions.orTrue
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
import org.matrix.android.sdk.internal.auth.version.Versions
import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices
import org.matrix.android.sdk.internal.auth.version.doesServerSupportQrCodeLogin
import org.matrix.android.sdk.internal.auth.version.doesServerSupportThreads
import org.matrix.android.sdk.internal.auth.version.isLoginAndRegistrationSupportedBySdk
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity
@ -134,6 +135,7 @@ internal class DefaultGetHomeServerCapabilitiesTask @Inject constructor(
}
homeServerCapabilitiesEntity.canUseThreading = /* capabilities?.threads?.enabled.orFalse() || */
getVersionResult?.doesServerSupportThreads().orFalse()
homeServerCapabilitiesEntity.canLoginWithQrCode = getVersionResult?.doesServerSupportQrCodeLogin().orFalse()
}
if (getMediaConfigResult != null) {

View file

@ -24,7 +24,6 @@ import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.viewModel
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.addFragment
import im.vector.app.core.extensions.addFragmentToBackstack
import im.vector.app.core.platform.SimpleFragmentActivity
import org.matrix.android.sdk.api.extensions.orFalse
import timber.log.Timber
@ -88,7 +87,7 @@ class QrCodeLoginActivity : SimpleFragmentActivity() {
}
private fun handleNavigateToStatusScreen() {
addFragmentToBackstack(
addFragment(
views.container,
QrCodeLoginStatusFragment::class.java,
tag = FRAGMENT_QR_CODE_STATUS_TAG

View file

@ -44,7 +44,7 @@ class QrCodeLoginShowQrCodeFragment : VectorBaseFragment<FragmentQrCodeLoginShow
private fun initCancelButton() {
views.qrCodeLoginShowQrCodeCancelButton.debouncedClicks {
parentFragmentManager.popBackStack()
activity?.onBackPressed()
}
}

View file

@ -45,7 +45,7 @@ class QrCodeLoginStatusFragment : VectorBaseFragment<FragmentQrCodeLoginStatusBi
private fun initCancelButton() {
views.qrCodeLoginStatusCancelButton.debouncedClicks {
parentFragmentManager.popBackStack()
activity?.onBackPressed()
}
}

View file

@ -117,6 +117,25 @@ class OnboardingViewModel @AssistedInject constructor(
}
}
private fun observeQrCodeLoginCapability() = viewModelScope.launch {
if (!vectorFeatures.isQrCodeLoginEnabled()) {
setState {
copy(
canLoginWithQrCode = false
)
}
} else {
homeServerConnectionConfigFactory.create(defaultHomeserverUrl)?.let {
val canLoginWithQrCode = authenticationService.isQrLoginSupported(it)
setState {
copy(
canLoginWithQrCode = canLoginWithQrCode
)
}
}
}
}
private val matrixOrgUrl = stringProvider.getString(R.string.matrix_org_server_url).ensureTrailingSlash()
private val defaultHomeserverUrl = matrixOrgUrl
@ -234,6 +253,7 @@ class OnboardingViewModel @AssistedInject constructor(
private fun handleSplashAction(action: OnboardingAction.SplashAction) {
setState { copy(onboardingFlow = action.onboardingFlow) }
continueToPageAfterSplash(action.onboardingFlow)
observeQrCodeLoginCapability()
}
private fun continueToPageAfterSplash(onboardingFlow: OnboardingFlow) {

View file

@ -58,7 +58,9 @@ data class OnboardingViewState(
val selectedAuthenticationState: SelectedAuthenticationState = SelectedAuthenticationState(),
@PersistState
val personalizationState: PersonalizationState = PersonalizationState()
val personalizationState: PersonalizationState = PersonalizationState(),
val canLoginWithQrCode: Boolean = false,
) : MavericksState
enum class OnboardingFlow {

View file

@ -74,7 +74,15 @@ class FtueAuthCombinedLoginFragment :
viewModel.handle(OnboardingAction.UserNameEnteredAction.Login(views.loginInput.content()))
}
views.loginForgotPassword.debouncedClicks { viewModel.handle(OnboardingAction.PostViewEvent(OnboardingViewEvents.OnForgetPasswordClicked)) }
if (vectorFeatures.isQrCodeLoginEnabled()) {
viewModel.onEach(OnboardingViewState::canLoginWithQrCode) {
configureQrCodeLoginButtonVisibility(it)
}
}
private fun configureQrCodeLoginButtonVisibility(canLoginWithQrCode: Boolean) {
if (canLoginWithQrCode) {
views.loginWithQrCode.isVisible = true
views.loginWithQrCode.debouncedClicks {
navigator
.openLoginWithQrCode(

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -112,12 +113,14 @@
android:id="@+id/deviceListHeaderSignInWithQrCode"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/deviceListOtherSessions"
app:sessionListHeaderShowLearnMore="false"
app:sessionsListHeaderDescription="@string/device_manager_sessions_sign_in_with_qr_code_description"
app:sessionsListHeaderTitle="@string/device_manager_sessions_sign_in_with_qr_code_title" />
app:sessionsListHeaderTitle="@string/device_manager_sessions_sign_in_with_qr_code_title"
tools:visibility="visible" />
<Button
android:id="@+id/deviceListHeaderScanQrCodeButton"
@ -126,9 +129,11 @@
android:layout_marginHorizontal="16dp"
android:layout_marginTop="12dp"
android:text="@string/qr_code_login_scan_qr_code_button"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/deviceListHeaderSignInWithQrCode" />
app:layout_constraintTop_toBottomOf="@id/deviceListHeaderSignInWithQrCode"
tools:visibility="visible" />
<Button
android:id="@+id/deviceListHeaderShowQrCodeButton"
@ -139,9 +144,11 @@
android:layout_marginTop="4dp"
android:layout_marginBottom="12dp"
android:text="@string/qr_code_login_show_qr_code_button"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/deviceListHeaderScanQrCodeButton" />
app:layout_constraintTop_toBottomOf="@id/deviceListHeaderScanQrCodeButton"
tools:visibility="visible" />
<include
android:id="@+id/waiting_view"