mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-22 01:15:54 +03:00
Merge pull request #7306 from vector-im/feature/mna/device-manager-extended-details
[Device Management] Render extended device info (PSG-773)
This commit is contained in:
commit
f8f416e979
23 changed files with 574 additions and 104 deletions
1
changelog.d/7294.wip
Normal file
1
changelog.d/7294.wip
Normal file
|
@ -0,0 +1 @@
|
|||
[Device Management] Render extended device info
|
|
@ -3314,6 +3314,13 @@
|
|||
<string name="device_manager_session_details_session_name">Session name</string>
|
||||
<string name="device_manager_session_details_session_id">Session ID</string>
|
||||
<string name="device_manager_session_details_session_last_activity">Last activity</string>
|
||||
<string name="device_manager_session_details_application">Application</string>
|
||||
<string name="device_manager_session_details_application_name">Name</string>
|
||||
<string name="device_manager_session_details_application_version">Version</string>
|
||||
<string name="device_manager_session_details_application_url">URL</string>
|
||||
<string name="device_manager_session_details_device_browser">Browser</string>
|
||||
<string name="device_manager_session_details_device_model">Model</string>
|
||||
<string name="device_manager_session_details_device_operating_system">Operating system</string>
|
||||
<string name="device_manager_session_details_device_ip_address">IP address</string>
|
||||
<string name="device_manager_session_rename">Rename session</string>
|
||||
<string name="device_manager_session_rename_edit_hint">Session name</string>
|
||||
|
|
|
@ -19,4 +19,4 @@ package im.vector.app.core.session.clientinfo
|
|||
/**
|
||||
* Prefix for the key account data event which holds client info.
|
||||
*/
|
||||
const val MATRIX_CLIENT_INFO_KEY_PREFIX = "io.element.matrix_client_information."
|
||||
internal const val MATRIX_CLIENT_INFO_KEY_PREFIX = "io.element.matrix_client_information."
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package im.vector.app.features.settings.devices.v2
|
||||
|
||||
import im.vector.app.core.session.clientinfo.MatrixClientInfoContent
|
||||
import im.vector.app.features.settings.devices.v2.details.extended.DeviceExtendedInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
||||
|
@ -27,4 +29,5 @@ data class DeviceFullInfo(
|
|||
val isInactive: Boolean,
|
||||
val isCurrentDevice: Boolean,
|
||||
val deviceExtendedInfo: DeviceExtendedInfo,
|
||||
val matrixClientInfo: MatrixClientInfoContent?,
|
||||
)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.app.features.settings.devices.v2
|
||||
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.session.clientinfo.GetMatrixClientInfoUseCase
|
||||
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
||||
import im.vector.app.features.settings.devices.v2.filter.FilterDevicesUseCase
|
||||
import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase
|
||||
|
@ -27,6 +28,7 @@ import kotlinx.coroutines.flow.Flow
|
|||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
import org.matrix.android.sdk.flow.flow
|
||||
|
@ -39,6 +41,7 @@ class GetDeviceFullInfoListUseCase @Inject constructor(
|
|||
private val getCurrentSessionCrossSigningInfoUseCase: GetCurrentSessionCrossSigningInfoUseCase,
|
||||
private val filterDevicesUseCase: FilterDevicesUseCase,
|
||||
private val parseDeviceUserAgentUseCase: ParseDeviceUserAgentUseCase,
|
||||
private val getMatrixClientInfoUseCase: GetMatrixClientInfoUseCase,
|
||||
) {
|
||||
|
||||
fun execute(filterType: DeviceManagerFilterType, excludeCurrentDevice: Boolean = false): Flow<List<DeviceFullInfo>> {
|
||||
|
@ -48,7 +51,7 @@ class GetDeviceFullInfoListUseCase @Inject constructor(
|
|||
session.flow().liveUserCryptoDevices(session.myUserId),
|
||||
session.flow().liveMyDevicesInfo()
|
||||
) { currentSessionCrossSigningInfo, cryptoList, infoList ->
|
||||
val deviceFullInfoList = convertToDeviceFullInfoList(currentSessionCrossSigningInfo, cryptoList, infoList)
|
||||
val deviceFullInfoList = convertToDeviceFullInfoList(session, currentSessionCrossSigningInfo, cryptoList, infoList)
|
||||
val excludedDeviceIds = if (excludeCurrentDevice) {
|
||||
listOf(currentSessionCrossSigningInfo.deviceId)
|
||||
} else {
|
||||
|
@ -62,6 +65,7 @@ class GetDeviceFullInfoListUseCase @Inject constructor(
|
|||
}
|
||||
|
||||
private fun convertToDeviceFullInfoList(
|
||||
session: Session,
|
||||
currentSessionCrossSigningInfo: CurrentSessionCrossSigningInfo,
|
||||
cryptoList: List<CryptoDeviceInfo>,
|
||||
infoList: List<DeviceInfo>,
|
||||
|
@ -73,8 +77,20 @@ class GetDeviceFullInfoListUseCase @Inject constructor(
|
|||
val roomEncryptionTrustLevel = getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo)
|
||||
val isInactive = checkIfSessionIsInactiveUseCase.execute(deviceInfo.lastSeenTs ?: 0)
|
||||
val isCurrentDevice = currentSessionCrossSigningInfo.deviceId == cryptoDeviceInfo?.deviceId
|
||||
val deviceUserAgent = parseDeviceUserAgentUseCase.execute(deviceInfo.getBestLastSeenUserAgent())
|
||||
DeviceFullInfo(deviceInfo, cryptoDeviceInfo, roomEncryptionTrustLevel, isInactive, isCurrentDevice, deviceUserAgent)
|
||||
val deviceExtendedInfo = parseDeviceUserAgentUseCase.execute(deviceInfo.getBestLastSeenUserAgent())
|
||||
val matrixClientInfo = deviceInfo.deviceId
|
||||
?.takeIf { it.isNotEmpty() }
|
||||
?.let { getMatrixClientInfoUseCase.execute(session, it) }
|
||||
|
||||
DeviceFullInfo(
|
||||
deviceInfo = deviceInfo,
|
||||
cryptoDeviceInfo = cryptoDeviceInfo,
|
||||
roomEncryptionTrustLevel = roomEncryptionTrustLevel,
|
||||
isInactive = isInactive,
|
||||
isCurrentDevice = isCurrentDevice,
|
||||
deviceExtendedInfo = deviceExtendedInfo,
|
||||
matrixClientInfo = matrixClientInfo
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package im.vector.app.features.settings.devices.v2
|
||||
|
||||
import im.vector.app.features.settings.devices.v2.details.extended.DeviceExtendedInfo
|
||||
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import javax.inject.Inject
|
||||
|
@ -139,13 +140,11 @@ class ParseDeviceUserAgentUseCase @Inject constructor() {
|
|||
}
|
||||
|
||||
private fun getBrowserVersion(browserSegments: List<String>, browserName: String): String? {
|
||||
// Chrome/104.0.3497.100 -> 104
|
||||
// e.g Chrome/104.0.3497.100 -> 104.0.3497.100
|
||||
return browserSegments
|
||||
.find { it.startsWith(browserName) }
|
||||
?.split("/")
|
||||
?.getOrNull(1)
|
||||
?.split(".")
|
||||
?.firstOrNull()
|
||||
}
|
||||
|
||||
private fun isEdge(browserSegments: List<String>): Boolean {
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import im.vector.app.core.session.clientinfo.MatrixClientInfoContent
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import javax.inject.Inject
|
||||
|
||||
class CheckIfSectionApplicationIsVisibleUseCase @Inject constructor() {
|
||||
|
||||
fun execute(matrixClientInfoContent: MatrixClientInfoContent?): Boolean {
|
||||
return matrixClientInfoContent?.name?.isNotEmpty().orFalse() ||
|
||||
matrixClientInfoContent?.version?.isNotEmpty().orFalse() ||
|
||||
matrixClientInfoContent?.url?.isNotEmpty().orFalse()
|
||||
}
|
||||
}
|
|
@ -16,13 +16,36 @@
|
|||
|
||||
package im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||
import im.vector.app.features.settings.devices.v2.details.extended.DeviceExtendedInfo
|
||||
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
import javax.inject.Inject
|
||||
|
||||
class CheckIfSectionDeviceIsVisibleUseCase @Inject constructor() {
|
||||
|
||||
fun execute(deviceInfo: DeviceInfo): Boolean {
|
||||
return deviceInfo.lastSeenIp?.isNotEmpty().orFalse()
|
||||
fun execute(deviceFullInfo: DeviceFullInfo): Boolean {
|
||||
val hasExtendedInfo = when (deviceFullInfo.deviceExtendedInfo.deviceType) {
|
||||
DeviceType.MOBILE -> hasAnyDeviceExtendedInfoMobile(deviceFullInfo.deviceExtendedInfo)
|
||||
DeviceType.WEB -> hasAnyDeviceExtendedInfoWeb(deviceFullInfo.deviceExtendedInfo)
|
||||
DeviceType.DESKTOP -> hasAnyDeviceExtendedInfoDesktop(deviceFullInfo.deviceExtendedInfo)
|
||||
DeviceType.UNKNOWN -> false
|
||||
}
|
||||
|
||||
return hasExtendedInfo || deviceFullInfo.deviceInfo.lastSeenIp?.isNotEmpty().orFalse()
|
||||
}
|
||||
|
||||
private fun hasAnyDeviceExtendedInfoMobile(deviceExtendedInfo: DeviceExtendedInfo): Boolean {
|
||||
return deviceExtendedInfo.deviceModel?.isNotEmpty().orFalse() ||
|
||||
deviceExtendedInfo.deviceOperatingSystem?.isNotEmpty().orFalse()
|
||||
}
|
||||
|
||||
private fun hasAnyDeviceExtendedInfoWeb(deviceExtendedInfo: DeviceExtendedInfo): Boolean {
|
||||
return deviceExtendedInfo.clientName?.isNotEmpty().orFalse() ||
|
||||
deviceExtendedInfo.deviceOperatingSystem?.isNotEmpty().orFalse()
|
||||
}
|
||||
|
||||
private fun hasAnyDeviceExtendedInfoDesktop(deviceExtendedInfo: DeviceExtendedInfo): Boolean {
|
||||
return deviceExtendedInfo.deviceOperatingSystem?.isNotEmpty().orFalse()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,17 +23,21 @@ import im.vector.app.R
|
|||
import im.vector.app.core.date.DateFormatKind
|
||||
import im.vector.app.core.date.VectorDateFormatter
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.core.session.clientinfo.MatrixClientInfoContent
|
||||
import im.vector.app.core.utils.DimensionConverter
|
||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
import javax.inject.Inject
|
||||
|
||||
class SessionDetailsController @Inject constructor(
|
||||
private val checkIfSectionSessionIsVisibleUseCase: CheckIfSectionSessionIsVisibleUseCase,
|
||||
private val checkIfSectionDeviceIsVisibleUseCase: CheckIfSectionDeviceIsVisibleUseCase,
|
||||
private val checkIfSectionApplicationIsVisibleUseCase: CheckIfSectionApplicationIsVisibleUseCase,
|
||||
private val stringProvider: StringProvider,
|
||||
private val dateFormatter: VectorDateFormatter,
|
||||
private val dimensionConverter: DimensionConverter,
|
||||
) : TypedEpoxyController<DeviceInfo>() {
|
||||
) : TypedEpoxyController<DeviceFullInfo>() {
|
||||
|
||||
var callback: Callback? = null
|
||||
|
||||
|
@ -41,15 +45,22 @@ class SessionDetailsController @Inject constructor(
|
|||
fun onItemLongClicked(content: String)
|
||||
}
|
||||
|
||||
override fun buildModels(data: DeviceInfo?) {
|
||||
data?.let { info ->
|
||||
val hasSectionSession = hasSectionSession(data)
|
||||
override fun buildModels(data: DeviceFullInfo?) {
|
||||
data?.let { fullInfo ->
|
||||
val deviceInfo = fullInfo.deviceInfo
|
||||
val matrixClientInfo = fullInfo.matrixClientInfo
|
||||
val hasSectionSession = hasSectionSession(deviceInfo)
|
||||
if (hasSectionSession) {
|
||||
buildSectionSession(info)
|
||||
buildSectionSession(deviceInfo)
|
||||
}
|
||||
|
||||
if (hasSectionDevice(data)) {
|
||||
buildSectionDevice(info, addExtraTopMargin = hasSectionSession)
|
||||
val hasApplicationSection = hasSectionApplication(matrixClientInfo)
|
||||
if (hasApplicationSection && matrixClientInfo != null) {
|
||||
buildSectionApplication(matrixClientInfo, addExtraTopMargin = hasSectionSession)
|
||||
}
|
||||
|
||||
if (hasSectionDevice(fullInfo)) {
|
||||
buildSectionDevice(fullInfo, addExtraTopMargin = hasSectionSession || hasApplicationSection)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,39 +94,126 @@ class SessionDetailsController @Inject constructor(
|
|||
}
|
||||
|
||||
private fun buildSectionSession(data: DeviceInfo) {
|
||||
val sessionName = data.displayName
|
||||
val sessionId = data.deviceId
|
||||
val sessionLastSeenTs = data.lastSeenTs
|
||||
val sessionName = data.displayName.orEmpty()
|
||||
val sessionId = data.deviceId.orEmpty()
|
||||
val sessionLastSeenTs = data.lastSeenTs ?: -1
|
||||
|
||||
buildHeaderItem(R.string.device_manager_session_title)
|
||||
|
||||
sessionName?.let {
|
||||
val hasDivider = sessionId != null || sessionLastSeenTs != null
|
||||
buildContentItem(R.string.device_manager_session_details_session_name, it, hasDivider)
|
||||
if (sessionName.isNotEmpty()) {
|
||||
val hasDivider = sessionId.isNotEmpty() || sessionLastSeenTs > 0
|
||||
buildContentItem(R.string.device_manager_session_details_session_name, sessionName, hasDivider)
|
||||
}
|
||||
sessionId?.let {
|
||||
val hasDivider = sessionLastSeenTs != null
|
||||
buildContentItem(R.string.device_manager_session_details_session_id, it, hasDivider)
|
||||
if (sessionId.isNotEmpty()) {
|
||||
val hasDivider = sessionLastSeenTs > 0
|
||||
buildContentItem(R.string.device_manager_session_details_session_id, sessionId, hasDivider)
|
||||
}
|
||||
sessionLastSeenTs?.let {
|
||||
val formattedDate = dateFormatter.format(it, DateFormatKind.MESSAGE_DETAIL)
|
||||
if (sessionLastSeenTs > 0) {
|
||||
val formattedDate = dateFormatter.format(sessionLastSeenTs, DateFormatKind.MESSAGE_DETAIL)
|
||||
val hasDivider = false
|
||||
buildContentItem(R.string.device_manager_session_details_session_last_activity, formattedDate, hasDivider)
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasSectionDevice(data: DeviceInfo): Boolean {
|
||||
private fun hasSectionApplication(matrixClientInfoContent: MatrixClientInfoContent?): Boolean {
|
||||
return checkIfSectionApplicationIsVisibleUseCase.execute(matrixClientInfoContent)
|
||||
}
|
||||
|
||||
private fun buildSectionApplication(matrixClientInfoContent: MatrixClientInfoContent, addExtraTopMargin: Boolean) {
|
||||
val name = matrixClientInfoContent.name.orEmpty()
|
||||
val version = matrixClientInfoContent.version.orEmpty()
|
||||
val url = matrixClientInfoContent.url.orEmpty()
|
||||
|
||||
buildHeaderItem(R.string.device_manager_session_details_application, addExtraTopMargin)
|
||||
|
||||
if (name.isNotEmpty()) {
|
||||
val hasDivider = version.isNotEmpty() || url.isNotEmpty()
|
||||
buildContentItem(R.string.device_manager_session_details_application_name, name, hasDivider)
|
||||
}
|
||||
if (version.isNotEmpty()) {
|
||||
val hasDivider = url.isNotEmpty()
|
||||
buildContentItem(R.string.device_manager_session_details_application_version, version, hasDivider)
|
||||
}
|
||||
if (url.isNotEmpty()) {
|
||||
val hasDivider = false
|
||||
buildContentItem(R.string.device_manager_session_details_application_url, url, hasDivider)
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasSectionDevice(data: DeviceFullInfo): Boolean {
|
||||
return checkIfSectionDeviceIsVisibleUseCase.execute(data)
|
||||
}
|
||||
|
||||
private fun buildSectionDevice(data: DeviceInfo, addExtraTopMargin: Boolean) {
|
||||
val lastSeenIp = data.lastSeenIp
|
||||
|
||||
private fun buildSectionDevice(data: DeviceFullInfo, addExtraTopMargin: Boolean) {
|
||||
buildHeaderItem(R.string.device_manager_device_title, addExtraTopMargin)
|
||||
|
||||
lastSeenIp?.let {
|
||||
when (data.deviceExtendedInfo.deviceType) {
|
||||
DeviceType.MOBILE -> buildSectionDeviceMobile(data)
|
||||
DeviceType.WEB -> buildSectionDeviceWeb(data)
|
||||
DeviceType.DESKTOP -> buildSectionDeviceDesktop(data)
|
||||
DeviceType.UNKNOWN -> buildSectionDeviceUnknown(data)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildSectionDeviceWeb(data: DeviceFullInfo) {
|
||||
val browserName = data.deviceExtendedInfo.clientName.orEmpty()
|
||||
val browserVersion = data.deviceExtendedInfo.clientVersion.orEmpty()
|
||||
val browser = "$browserName $browserVersion"
|
||||
val operatingSystem = data.deviceExtendedInfo.deviceOperatingSystem.orEmpty()
|
||||
val lastSeenIp = data.deviceInfo.lastSeenIp.orEmpty()
|
||||
|
||||
if (browser.isNotEmpty()) {
|
||||
val hasDivider = operatingSystem.isNotEmpty() || lastSeenIp.isNotEmpty()
|
||||
buildContentItem(R.string.device_manager_session_details_device_browser, browser, hasDivider)
|
||||
}
|
||||
|
||||
if (operatingSystem.isNotEmpty()) {
|
||||
val hasDivider = lastSeenIp.isNotEmpty()
|
||||
buildContentItem(R.string.device_manager_session_details_device_operating_system, operatingSystem, hasDivider)
|
||||
}
|
||||
|
||||
buildIpAddressContentItem(lastSeenIp)
|
||||
}
|
||||
|
||||
private fun buildSectionDeviceDesktop(data: DeviceFullInfo) {
|
||||
val operatingSystem = data.deviceExtendedInfo.deviceOperatingSystem.orEmpty()
|
||||
val lastSeenIp = data.deviceInfo.lastSeenIp.orEmpty()
|
||||
|
||||
if (operatingSystem.isNotEmpty()) {
|
||||
val hasDivider = lastSeenIp.isNotEmpty()
|
||||
buildContentItem(R.string.device_manager_session_details_device_operating_system, operatingSystem, hasDivider)
|
||||
}
|
||||
|
||||
buildIpAddressContentItem(lastSeenIp)
|
||||
}
|
||||
|
||||
private fun buildSectionDeviceMobile(data: DeviceFullInfo) {
|
||||
val model = data.deviceExtendedInfo.deviceModel.orEmpty()
|
||||
val operatingSystem = data.deviceExtendedInfo.deviceOperatingSystem.orEmpty()
|
||||
val lastSeenIp = data.deviceInfo.lastSeenIp.orEmpty()
|
||||
|
||||
if (model.isNotEmpty()) {
|
||||
val hasDivider = operatingSystem.isNotEmpty() || lastSeenIp.isNotEmpty()
|
||||
buildContentItem(R.string.device_manager_session_details_device_model, model, hasDivider)
|
||||
}
|
||||
|
||||
if (operatingSystem.isNotEmpty()) {
|
||||
val hasDivider = lastSeenIp.isNotEmpty()
|
||||
buildContentItem(R.string.device_manager_session_details_device_operating_system, operatingSystem, hasDivider)
|
||||
}
|
||||
|
||||
buildIpAddressContentItem(lastSeenIp)
|
||||
}
|
||||
|
||||
private fun buildSectionDeviceUnknown(data: DeviceFullInfo) {
|
||||
val lastSeenIp = data.deviceInfo.lastSeenIp.orEmpty()
|
||||
buildIpAddressContentItem(lastSeenIp)
|
||||
}
|
||||
|
||||
private fun buildIpAddressContentItem(lastSeenIp: String) {
|
||||
if (lastSeenIp.isNotEmpty()) {
|
||||
val hasDivider = false
|
||||
buildContentItem(R.string.device_manager_session_details_device_ip_address, it, hasDivider)
|
||||
buildContentItem(R.string.device_manager_session_details_device_ip_address, lastSeenIp, hasDivider)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ import im.vector.app.core.extensions.configureWith
|
|||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.core.platform.showOptimizedSnackbar
|
||||
import im.vector.app.databinding.FragmentSessionDetailsBinding
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
|
@ -92,16 +92,16 @@ class SessionDetailsFragment :
|
|||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
if (state.deviceInfo is Success) {
|
||||
renderSessionDetails(state.deviceInfo.invoke())
|
||||
if (state.deviceFullInfo is Success) {
|
||||
renderSessionDetails(state.deviceFullInfo.invoke())
|
||||
} else {
|
||||
hideSessionDetails()
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderSessionDetails(deviceInfo: DeviceInfo) {
|
||||
private fun renderSessionDetails(deviceFullInfo: DeviceFullInfo) {
|
||||
views.sessionDetails.isVisible = true
|
||||
sessionDetailsController.setData(deviceInfo)
|
||||
sessionDetailsController.setData(deviceFullInfo)
|
||||
}
|
||||
|
||||
private fun hideSessionDetails() {
|
||||
|
|
|
@ -48,7 +48,7 @@ class SessionDetailsViewModel @AssistedInject constructor(
|
|||
|
||||
private fun observeSessionInfo(deviceId: String) {
|
||||
getDeviceFullInfoUseCase.execute(deviceId)
|
||||
.onEach { setState { copy(deviceInfo = Success(it.deviceInfo)) } }
|
||||
.onEach { setState { copy(deviceFullInfo = Success(it)) } }
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
|
|
|
@ -19,11 +19,11 @@ package im.vector.app.features.settings.devices.v2.details
|
|||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MavericksState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||
|
||||
data class SessionDetailsViewState(
|
||||
val deviceId: String,
|
||||
val deviceInfo: Async<DeviceInfo> = Uninitialized,
|
||||
val deviceFullInfo: Async<DeviceFullInfo> = Uninitialized,
|
||||
) : MavericksState {
|
||||
constructor(args: SessionDetailsArgs) : this(
|
||||
deviceId = args.deviceId
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.app.features.settings.devices.v2
|
||||
package im.vector.app.features.settings.devices.v2.details.extended
|
||||
|
||||
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||
|
|
@ -18,6 +18,7 @@ package im.vector.app.features.settings.devices.v2.overview
|
|||
|
||||
import androidx.lifecycle.asFlow
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.session.clientinfo.GetMatrixClientInfoUseCase
|
||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||
import im.vector.app.features.settings.devices.v2.ParseDeviceUserAgentUseCase
|
||||
import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase
|
||||
|
@ -36,6 +37,7 @@ class GetDeviceFullInfoUseCase @Inject constructor(
|
|||
private val getEncryptionTrustLevelForDeviceUseCase: GetEncryptionTrustLevelForDeviceUseCase,
|
||||
private val checkIfSessionIsInactiveUseCase: CheckIfSessionIsInactiveUseCase,
|
||||
private val parseDeviceUserAgentUseCase: ParseDeviceUserAgentUseCase,
|
||||
private val getMatrixClientInfoUseCase: GetMatrixClientInfoUseCase,
|
||||
) {
|
||||
|
||||
fun execute(deviceId: String): Flow<DeviceFullInfo> {
|
||||
|
@ -52,6 +54,10 @@ class GetDeviceFullInfoUseCase @Inject constructor(
|
|||
val isInactive = checkIfSessionIsInactiveUseCase.execute(info.lastSeenTs ?: 0)
|
||||
val isCurrentDevice = currentSessionCrossSigningInfo.deviceId == cryptoInfo.deviceId
|
||||
val deviceUserAgent = parseDeviceUserAgentUseCase.execute(info.getBestLastSeenUserAgent())
|
||||
val matrixClientInfo = info.deviceId
|
||||
?.takeIf { it.isNotEmpty() }
|
||||
?.let { getMatrixClientInfoUseCase.execute(session, it) }
|
||||
|
||||
DeviceFullInfo(
|
||||
deviceInfo = info,
|
||||
cryptoDeviceInfo = cryptoInfo,
|
||||
|
@ -59,6 +65,7 @@ class GetDeviceFullInfoUseCase @Inject constructor(
|
|||
isInactive = isInactive,
|
||||
isCurrentDevice = isCurrentDevice,
|
||||
deviceExtendedInfo = deviceUserAgent,
|
||||
matrixClientInfo = matrixClientInfo
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
|
|
@ -19,6 +19,8 @@ package im.vector.app.features.settings.devices.v2
|
|||
import android.os.SystemClock
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.test.MavericksTestRule
|
||||
import im.vector.app.core.session.clientinfo.MatrixClientInfoContent
|
||||
import im.vector.app.features.settings.devices.v2.details.extended.DeviceExtendedInfo
|
||||
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||
import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase
|
||||
import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo
|
||||
|
@ -53,7 +55,7 @@ class DevicesViewModelTest {
|
|||
private val fakeActiveSessionHolder = FakeActiveSessionHolder()
|
||||
private val getCurrentSessionCrossSigningInfoUseCase = mockk<GetCurrentSessionCrossSigningInfoUseCase>()
|
||||
private val getDeviceFullInfoListUseCase = mockk<GetDeviceFullInfoListUseCase>()
|
||||
private val refreshDevicesUseCase = mockk<RefreshDevicesUseCase>()
|
||||
private val refreshDevicesUseCase = mockk<RefreshDevicesUseCase>(relaxUnitFun = true)
|
||||
private val refreshDevicesOnCryptoDevicesChangeUseCase = mockk<RefreshDevicesOnCryptoDevicesChangeUseCase>()
|
||||
private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk<CheckIfCurrentSessionCanBeVerifiedUseCase>()
|
||||
|
||||
|
@ -245,7 +247,8 @@ class DevicesViewModelTest {
|
|||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
||||
isInactive = false,
|
||||
isCurrentDevice = true,
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE),
|
||||
matrixClientInfo = MatrixClientInfoContent(),
|
||||
)
|
||||
val deviceFullInfo2 = DeviceFullInfo(
|
||||
deviceInfo = mockk(),
|
||||
|
@ -253,7 +256,8 @@ class DevicesViewModelTest {
|
|||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
|
||||
isInactive = true,
|
||||
isCurrentDevice = false,
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE),
|
||||
matrixClientInfo = MatrixClientInfoContent(),
|
||||
)
|
||||
val deviceFullInfoList = listOf(deviceFullInfo1, deviceFullInfo2)
|
||||
val deviceFullInfoListFlow = flowOf(deviceFullInfoList)
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
|
||||
package im.vector.app.features.settings.devices.v2
|
||||
|
||||
import im.vector.app.core.session.clientinfo.GetMatrixClientInfoUseCase
|
||||
import im.vector.app.core.session.clientinfo.MatrixClientInfoContent
|
||||
import im.vector.app.features.settings.devices.v2.details.extended.DeviceExtendedInfo
|
||||
import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType
|
||||
import im.vector.app.features.settings.devices.v2.filter.FilterDevicesUseCase
|
||||
import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase
|
||||
|
@ -55,6 +58,7 @@ class GetDeviceFullInfoListUseCaseTest {
|
|||
private val getCurrentSessionCrossSigningInfoUseCase = mockk<GetCurrentSessionCrossSigningInfoUseCase>()
|
||||
private val filterDevicesUseCase = mockk<FilterDevicesUseCase>()
|
||||
private val parseDeviceUserAgentUseCase = mockk<ParseDeviceUserAgentUseCase>()
|
||||
private val getMatrixClientInfoUseCase = mockk<GetMatrixClientInfoUseCase>()
|
||||
|
||||
private val getDeviceFullInfoListUseCase = GetDeviceFullInfoListUseCase(
|
||||
activeSessionHolder = fakeActiveSessionHolder.instance,
|
||||
|
@ -63,6 +67,7 @@ class GetDeviceFullInfoListUseCaseTest {
|
|||
getCurrentSessionCrossSigningInfoUseCase = getCurrentSessionCrossSigningInfoUseCase,
|
||||
filterDevicesUseCase = filterDevicesUseCase,
|
||||
parseDeviceUserAgentUseCase = parseDeviceUserAgentUseCase,
|
||||
getMatrixClientInfoUseCase = getMatrixClientInfoUseCase,
|
||||
)
|
||||
|
||||
@Before
|
||||
|
@ -108,13 +113,17 @@ class GetDeviceFullInfoListUseCaseTest {
|
|||
)
|
||||
val deviceInfoList = listOf(deviceInfo1, deviceInfo2, deviceInfo3)
|
||||
every { fakeFlowSession.liveMyDevicesInfo() } returns flowOf(deviceInfoList)
|
||||
val matrixClientInfo1 = givenAMatrixClientInfo(A_DEVICE_ID_1)
|
||||
val matrixClientInfo2 = givenAMatrixClientInfo(A_DEVICE_ID_2)
|
||||
val matrixClientInfo3 = givenAMatrixClientInfo(A_DEVICE_ID_3)
|
||||
val expectedResult1 = DeviceFullInfo(
|
||||
deviceInfo = deviceInfo1,
|
||||
cryptoDeviceInfo = cryptoDeviceInfo1,
|
||||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
||||
isInactive = true,
|
||||
isCurrentDevice = true,
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE),
|
||||
matrixClientInfo = matrixClientInfo1,
|
||||
)
|
||||
val expectedResult2 = DeviceFullInfo(
|
||||
deviceInfo = deviceInfo2,
|
||||
|
@ -122,7 +131,8 @@ class GetDeviceFullInfoListUseCaseTest {
|
|||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
||||
isInactive = false,
|
||||
isCurrentDevice = false,
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE),
|
||||
matrixClientInfo = matrixClientInfo2,
|
||||
)
|
||||
val expectedResult3 = DeviceFullInfo(
|
||||
deviceInfo = deviceInfo3,
|
||||
|
@ -130,7 +140,8 @@ class GetDeviceFullInfoListUseCaseTest {
|
|||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
|
||||
isInactive = false,
|
||||
isCurrentDevice = false,
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE),
|
||||
matrixClientInfo = matrixClientInfo3,
|
||||
)
|
||||
val expectedResult = listOf(expectedResult3, expectedResult2, expectedResult1)
|
||||
every { filterDevicesUseCase.execute(any(), any()) } returns expectedResult
|
||||
|
@ -152,6 +163,9 @@ class GetDeviceFullInfoListUseCaseTest {
|
|||
checkIfSessionIsInactiveUseCase.execute(A_TIMESTAMP_1)
|
||||
checkIfSessionIsInactiveUseCase.execute(A_TIMESTAMP_2)
|
||||
checkIfSessionIsInactiveUseCase.execute(A_TIMESTAMP_3)
|
||||
getMatrixClientInfoUseCase.execute(fakeActiveSessionHolder.fakeSession, A_DEVICE_ID_1)
|
||||
getMatrixClientInfoUseCase.execute(fakeActiveSessionHolder.fakeSession, A_DEVICE_ID_2)
|
||||
getMatrixClientInfoUseCase.execute(fakeActiveSessionHolder.fakeSession, A_DEVICE_ID_3)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,4 +215,10 @@ class GetDeviceFullInfoListUseCaseTest {
|
|||
|
||||
return deviceInfo
|
||||
}
|
||||
|
||||
private fun givenAMatrixClientInfo(deviceId: String): MatrixClientInfoContent {
|
||||
val matrixClientInfo = mockk<MatrixClientInfoContent>()
|
||||
every { getMatrixClientInfoUseCase.execute(fakeActiveSessionHolder.fakeSession, deviceId) } returns matrixClientInfo
|
||||
return matrixClientInfo
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package im.vector.app.features.settings.devices.v2
|
||||
|
||||
import im.vector.app.features.settings.devices.v2.details.extended.DeviceExtendedInfo
|
||||
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.junit.Test
|
||||
|
@ -61,8 +62,8 @@ private val A_USER_AGENT_LIST_FOR_DESKTOP = listOf(
|
|||
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) ElementNightly/2022091301 Chrome/104.0.5112.102 Electron/20.1.1 Safari/537.36",
|
||||
)
|
||||
private val AN_EXPECTED_RESULT_LIST_FOR_DESKTOP = listOf(
|
||||
DeviceExtendedInfo(DeviceType.DESKTOP, null, "Macintosh", "Electron", "20"),
|
||||
DeviceExtendedInfo(DeviceType.DESKTOP, null, "Windows NT 10.0", "Electron", "20"),
|
||||
DeviceExtendedInfo(DeviceType.DESKTOP, null, "Macintosh", "Electron", "20.1.1"),
|
||||
DeviceExtendedInfo(DeviceType.DESKTOP, null, "Windows NT 10.0", "Electron", "20.1.1"),
|
||||
)
|
||||
|
||||
private val A_USER_AGENT_LIST_FOR_WEB = listOf(
|
||||
|
@ -77,15 +78,15 @@ private val A_USER_AGENT_LIST_FOR_WEB = listOf(
|
|||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246",
|
||||
)
|
||||
private val AN_EXPECTED_RESULT_LIST_FOR_WEB = listOf(
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "Macintosh", "Chrome", "104"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "Windows NT 10.0", "Chrome", "104"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "Macintosh", "Firefox", "39"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "Macintosh", "Safari", "8"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "Android 9", "Chrome", "69"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "iPad", "Safari", "8"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "iPhone", "Safari", "8"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "Windows NT 6.0", "Firefox", "40"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "Windows NT 10.0", "Edge", "12"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "Macintosh", "Chrome", "104.0.5112.102"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "Windows NT 10.0", "Chrome", "104.0.5112.102"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "Macintosh", "Firefox", "39.0"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "Macintosh", "Safari", "8.0.3"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "Android 9", "Chrome", "69.0.3497.100"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "iPad", "Safari", "8.0"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "iPhone", "Safari", "8.0"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "Windows NT 6.0", "Firefox", "40.0"),
|
||||
DeviceExtendedInfo(DeviceType.WEB, null, "Windows NT 10.0", "Edge", "12.246"),
|
||||
)
|
||||
|
||||
private val AN_UNKNOWN_USER_AGENT_LIST = listOf(
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
*
|
||||
* 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 im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import im.vector.app.core.session.clientinfo.MatrixClientInfoContent
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.junit.Test
|
||||
|
||||
private const val AN_APP_NAME = "app-name"
|
||||
private const val AN_APP_VERSION = "app-version"
|
||||
private const val AN_APP_URL = "app-url"
|
||||
|
||||
class CheckIfSectionApplicationIsVisibleUseCaseTest {
|
||||
|
||||
private val checkIfSectionApplicationIsVisibleUseCase = CheckIfSectionApplicationIsVisibleUseCase()
|
||||
|
||||
@Test
|
||||
fun `given client info with name, version or url when checking is application section is visible then it returns true`() {
|
||||
// Given
|
||||
val clientInfoList = listOf(
|
||||
givenAClientInfo(
|
||||
name = AN_APP_NAME,
|
||||
version = null,
|
||||
url = null,
|
||||
),
|
||||
givenAClientInfo(
|
||||
name = null,
|
||||
version = AN_APP_VERSION,
|
||||
url = null,
|
||||
),
|
||||
givenAClientInfo(
|
||||
name = null,
|
||||
version = null,
|
||||
url = AN_APP_URL,
|
||||
),
|
||||
givenAClientInfo(
|
||||
name = AN_APP_NAME,
|
||||
version = AN_APP_VERSION,
|
||||
url = null,
|
||||
),
|
||||
givenAClientInfo(
|
||||
name = AN_APP_NAME,
|
||||
version = null,
|
||||
url = AN_APP_URL,
|
||||
),
|
||||
givenAClientInfo(
|
||||
name = null,
|
||||
version = AN_APP_VERSION,
|
||||
url = AN_APP_URL,
|
||||
),
|
||||
givenAClientInfo(
|
||||
name = AN_APP_NAME,
|
||||
version = AN_APP_VERSION,
|
||||
url = AN_APP_URL,
|
||||
),
|
||||
)
|
||||
|
||||
clientInfoList.forEach { clientInfo ->
|
||||
// When
|
||||
val result = checkIfSectionApplicationIsVisibleUseCase.execute(clientInfo)
|
||||
|
||||
// Then
|
||||
result shouldBeEqualTo true
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given client info with missing application info when checking is application section is visible then it returns false`() {
|
||||
// Given
|
||||
val clientInfoList = listOf(
|
||||
givenAClientInfo(
|
||||
name = null,
|
||||
version = null,
|
||||
url = null,
|
||||
),
|
||||
givenAClientInfo(
|
||||
name = "",
|
||||
version = null,
|
||||
url = null,
|
||||
),
|
||||
givenAClientInfo(
|
||||
name = null,
|
||||
version = "",
|
||||
url = null,
|
||||
),
|
||||
givenAClientInfo(
|
||||
name = null,
|
||||
version = null,
|
||||
url = "",
|
||||
),
|
||||
givenAClientInfo(
|
||||
name = "",
|
||||
version = "",
|
||||
url = null,
|
||||
),
|
||||
givenAClientInfo(
|
||||
name = "",
|
||||
version = null,
|
||||
url = "",
|
||||
),
|
||||
givenAClientInfo(
|
||||
name = null,
|
||||
version = "",
|
||||
url = "",
|
||||
),
|
||||
givenAClientInfo(
|
||||
name = "",
|
||||
version = "",
|
||||
url = "",
|
||||
),
|
||||
)
|
||||
|
||||
clientInfoList.forEach { clientInfo ->
|
||||
// When
|
||||
val result = checkIfSectionApplicationIsVisibleUseCase.execute(clientInfo)
|
||||
|
||||
// Then
|
||||
result shouldBeEqualTo false
|
||||
}
|
||||
}
|
||||
|
||||
private fun givenAClientInfo(
|
||||
name: String?,
|
||||
version: String?,
|
||||
url: String?,
|
||||
) = MatrixClientInfoContent(
|
||||
name = name,
|
||||
version = version,
|
||||
url = url,
|
||||
)
|
||||
}
|
|
@ -16,44 +16,116 @@
|
|||
|
||||
package im.vector.app.features.settings.devices.v2.details
|
||||
|
||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||
import im.vector.app.features.settings.devices.v2.details.extended.DeviceExtendedInfo
|
||||
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.junit.Test
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
|
||||
private const val AN_IP_ADDRESS = "ip-address"
|
||||
private const val A_DEVICE_MODEL = "device-model"
|
||||
private const val A_DEVICE_OPERATING_SYSTEM = "device-operating-system"
|
||||
private const val A_CLIENT_NAME = "client-name"
|
||||
|
||||
class CheckIfSectionDeviceIsVisibleUseCaseTest {
|
||||
|
||||
private val checkIfSectionDeviceIsVisibleUseCase = CheckIfSectionDeviceIsVisibleUseCase()
|
||||
|
||||
@Test
|
||||
fun `given device info with Ip address when checking is device section is visible then it returns true`() = runTest {
|
||||
// Given
|
||||
val deviceInfo = givenADeviceInfo(AN_IP_ADDRESS)
|
||||
fun `given device of any type with Ip address when checking if device section is visible then it returns true`() {
|
||||
DeviceType.values().forEach { deviceType ->
|
||||
// Given
|
||||
val deviceExtendedInfo = givenAnExtendedDeviceInfo(deviceType)
|
||||
val deviceFullInfo = givenADeviceFullInfo(deviceExtendedInfo)
|
||||
val deviceInfo = givenADeviceInfo(ipAddress = AN_IP_ADDRESS)
|
||||
every { deviceFullInfo.deviceInfo } returns deviceInfo
|
||||
|
||||
// When
|
||||
val result = checkIfSectionDeviceIsVisibleUseCase.execute(deviceInfo)
|
||||
// When
|
||||
val result = checkIfSectionDeviceIsVisibleUseCase.execute(deviceFullInfo)
|
||||
|
||||
// Then
|
||||
result shouldBeEqualTo true
|
||||
// Then
|
||||
result shouldBeEqualTo true
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given device info with empty or null Ip address when checking is device section is visible then it returns false`() = runTest {
|
||||
fun `given device of any type with empty or null Ip address and no extended info when checking if device section is visible then it returns false`() {
|
||||
DeviceType.values().forEach { deviceType ->
|
||||
// Given
|
||||
val deviceExtendedInfo = givenAnExtendedDeviceInfo(deviceType)
|
||||
val deviceFullInfo1 = givenADeviceFullInfo(deviceExtendedInfo)
|
||||
val deviceFullInfo2 = givenADeviceFullInfo(deviceExtendedInfo)
|
||||
val deviceInfo1 = givenADeviceInfo(ipAddress = "")
|
||||
val deviceInfo2 = givenADeviceInfo(ipAddress = null)
|
||||
every { deviceFullInfo1.deviceInfo } returns deviceInfo1
|
||||
every { deviceFullInfo2.deviceInfo } returns deviceInfo2
|
||||
|
||||
// When
|
||||
val result1 = checkIfSectionDeviceIsVisibleUseCase.execute(deviceFullInfo1)
|
||||
val result2 = checkIfSectionDeviceIsVisibleUseCase.execute(deviceFullInfo2)
|
||||
|
||||
// Then
|
||||
result1 shouldBeEqualTo false
|
||||
result2 shouldBeEqualTo false
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given device of any type with extended info when checking if device section is visible then it returns true`() {
|
||||
// Given
|
||||
val deviceInfo1 = givenADeviceInfo("")
|
||||
val deviceInfo2 = givenADeviceInfo(null)
|
||||
val deviceExtendedInfoList = listOf(
|
||||
givenAnExtendedDeviceInfo(
|
||||
DeviceType.MOBILE,
|
||||
deviceModel = A_DEVICE_MODEL,
|
||||
),
|
||||
givenAnExtendedDeviceInfo(
|
||||
DeviceType.MOBILE,
|
||||
deviceOperatingSystem = A_DEVICE_OPERATING_SYSTEM,
|
||||
),
|
||||
givenAnExtendedDeviceInfo(
|
||||
DeviceType.MOBILE,
|
||||
deviceModel = A_DEVICE_MODEL,
|
||||
deviceOperatingSystem = A_DEVICE_OPERATING_SYSTEM,
|
||||
),
|
||||
givenAnExtendedDeviceInfo(
|
||||
DeviceType.DESKTOP,
|
||||
deviceOperatingSystem = A_DEVICE_OPERATING_SYSTEM,
|
||||
),
|
||||
givenAnExtendedDeviceInfo(
|
||||
DeviceType.WEB,
|
||||
clientName = A_CLIENT_NAME,
|
||||
),
|
||||
givenAnExtendedDeviceInfo(
|
||||
DeviceType.WEB,
|
||||
deviceOperatingSystem = A_DEVICE_OPERATING_SYSTEM,
|
||||
),
|
||||
givenAnExtendedDeviceInfo(
|
||||
DeviceType.WEB,
|
||||
clientName = A_CLIENT_NAME,
|
||||
deviceOperatingSystem = A_DEVICE_OPERATING_SYSTEM,
|
||||
),
|
||||
)
|
||||
|
||||
// When
|
||||
val result1 = checkIfSectionDeviceIsVisibleUseCase.execute(deviceInfo1)
|
||||
val result2 = checkIfSectionDeviceIsVisibleUseCase.execute(deviceInfo2)
|
||||
deviceExtendedInfoList.forEach { deviceExtendedInfo ->
|
||||
val deviceFullInfo = givenADeviceFullInfo(deviceExtendedInfo)
|
||||
val deviceInfo = givenADeviceInfo(ipAddress = null)
|
||||
every { deviceFullInfo.deviceInfo } returns deviceInfo
|
||||
|
||||
// Then
|
||||
result1 shouldBeEqualTo false
|
||||
result2 shouldBeEqualTo false
|
||||
// When
|
||||
val result = checkIfSectionDeviceIsVisibleUseCase.execute(deviceFullInfo)
|
||||
|
||||
// Then
|
||||
result shouldBeEqualTo true
|
||||
}
|
||||
}
|
||||
|
||||
private fun givenADeviceFullInfo(deviceExtendedInfo: DeviceExtendedInfo): DeviceFullInfo {
|
||||
val deviceFullInfo = mockk<DeviceFullInfo>()
|
||||
every { deviceFullInfo.deviceExtendedInfo } returns deviceExtendedInfo
|
||||
return deviceFullInfo
|
||||
}
|
||||
|
||||
private fun givenADeviceInfo(ipAddress: String?): DeviceInfo {
|
||||
|
@ -61,4 +133,20 @@ class CheckIfSectionDeviceIsVisibleUseCaseTest {
|
|||
every { info.lastSeenIp } returns ipAddress
|
||||
return info
|
||||
}
|
||||
|
||||
private fun givenAnExtendedDeviceInfo(
|
||||
deviceType: DeviceType,
|
||||
clientName: String? = null,
|
||||
clientVersion: String? = null,
|
||||
deviceOperatingSystem: String? = null,
|
||||
deviceModel: String? = null,
|
||||
): DeviceExtendedInfo {
|
||||
return DeviceExtendedInfo(
|
||||
deviceType = deviceType,
|
||||
clientName = clientName,
|
||||
clientVersion = clientVersion,
|
||||
deviceOperatingSystem = deviceOperatingSystem,
|
||||
deviceModel = deviceModel,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ package im.vector.app.features.settings.devices.v2.details
|
|||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.junit.Test
|
||||
import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo
|
||||
|
@ -32,7 +31,7 @@ class CheckIfSectionSessionIsVisibleUseCaseTest {
|
|||
private val checkIfSectionSessionIsVisibleUseCase = CheckIfSectionSessionIsVisibleUseCase()
|
||||
|
||||
@Test
|
||||
fun `given device info with name, id or lastSeenTs when checking is session section is visible then it returns true`() = runTest {
|
||||
fun `given device info with name, id or lastSeenTs when checking is session section is visible then it returns true`() {
|
||||
// Given
|
||||
val deviceInfoList = listOf(
|
||||
givenADeviceInfo(
|
||||
|
@ -82,7 +81,7 @@ class CheckIfSectionSessionIsVisibleUseCaseTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `given device info with missing session info when checking is session section is visible then it returns true`() = runTest {
|
||||
fun `given device info with missing session info when checking is session section is visible then it returns false`() {
|
||||
// Given
|
||||
val deviceInfoList = listOf(
|
||||
givenADeviceInfo(
|
||||
|
|
|
@ -57,12 +57,10 @@ class SessionDetailsViewModelTest {
|
|||
fun `given the viewModel has been initialized then viewState is updated with session info`() {
|
||||
// Given
|
||||
val deviceFullInfo = mockk<DeviceFullInfo>()
|
||||
val deviceInfo = mockk<DeviceInfo>()
|
||||
every { deviceFullInfo.deviceInfo } returns deviceInfo
|
||||
every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo)
|
||||
val expectedState = SessionDetailsViewState(
|
||||
deviceId = A_SESSION_ID,
|
||||
deviceInfo = Success(deviceInfo)
|
||||
deviceFullInfo = Success(deviceFullInfo)
|
||||
)
|
||||
|
||||
// When
|
||||
|
|
|
@ -16,8 +16,9 @@
|
|||
|
||||
package im.vector.app.features.settings.devices.v2.filter
|
||||
|
||||
import im.vector.app.features.settings.devices.v2.DeviceExtendedInfo
|
||||
import im.vector.app.core.session.clientinfo.MatrixClientInfoContent
|
||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||
import im.vector.app.features.settings.devices.v2.details.extended.DeviceExtendedInfo
|
||||
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.amshove.kluent.shouldContainAll
|
||||
|
@ -37,7 +38,8 @@ private val activeVerifiedDevice = DeviceFullInfo(
|
|||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
||||
isInactive = false,
|
||||
isCurrentDevice = true,
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE),
|
||||
matrixClientInfo = MatrixClientInfoContent(),
|
||||
)
|
||||
private val inactiveVerifiedDevice = DeviceFullInfo(
|
||||
deviceInfo = DeviceInfo(deviceId = "INACTIVE_VERIFIED_DEVICE"),
|
||||
|
@ -49,7 +51,8 @@ private val inactiveVerifiedDevice = DeviceFullInfo(
|
|||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted,
|
||||
isInactive = true,
|
||||
isCurrentDevice = false,
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE),
|
||||
matrixClientInfo = MatrixClientInfoContent(),
|
||||
)
|
||||
private val activeUnverifiedDevice = DeviceFullInfo(
|
||||
deviceInfo = DeviceInfo(deviceId = "ACTIVE_UNVERIFIED_DEVICE"),
|
||||
|
@ -61,7 +64,8 @@ private val activeUnverifiedDevice = DeviceFullInfo(
|
|||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
|
||||
isInactive = false,
|
||||
isCurrentDevice = false,
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE),
|
||||
matrixClientInfo = MatrixClientInfoContent(),
|
||||
)
|
||||
private val inactiveUnverifiedDevice = DeviceFullInfo(
|
||||
deviceInfo = DeviceInfo(deviceId = "INACTIVE_UNVERIFIED_DEVICE"),
|
||||
|
@ -73,7 +77,8 @@ private val inactiveUnverifiedDevice = DeviceFullInfo(
|
|||
roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning,
|
||||
isInactive = true,
|
||||
isCurrentDevice = false,
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE),
|
||||
matrixClientInfo = MatrixClientInfoContent(),
|
||||
)
|
||||
|
||||
private val devices = listOf(
|
||||
|
|
|
@ -18,9 +18,11 @@ package im.vector.app.features.settings.devices.v2.overview
|
|||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.asFlow
|
||||
import im.vector.app.features.settings.devices.v2.DeviceExtendedInfo
|
||||
import im.vector.app.core.session.clientinfo.GetMatrixClientInfoUseCase
|
||||
import im.vector.app.core.session.clientinfo.MatrixClientInfoContent
|
||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||
import im.vector.app.features.settings.devices.v2.ParseDeviceUserAgentUseCase
|
||||
import im.vector.app.features.settings.devices.v2.details.extended.DeviceExtendedInfo
|
||||
import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase
|
||||
import im.vector.app.features.settings.devices.v2.list.DeviceType
|
||||
import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo
|
||||
|
@ -57,6 +59,7 @@ class GetDeviceFullInfoUseCaseTest {
|
|||
private val checkIfSessionIsInactiveUseCase = mockk<CheckIfSessionIsInactiveUseCase>()
|
||||
private val fakeFlowLiveDataConversions = FakeFlowLiveDataConversions()
|
||||
private val parseDeviceUserAgentUseCase = mockk<ParseDeviceUserAgentUseCase>()
|
||||
private val getMatrixClientInfoUseCase = mockk<GetMatrixClientInfoUseCase>()
|
||||
|
||||
private val getDeviceFullInfoUseCase = GetDeviceFullInfoUseCase(
|
||||
activeSessionHolder = fakeActiveSessionHolder.instance,
|
||||
|
@ -64,6 +67,7 @@ class GetDeviceFullInfoUseCaseTest {
|
|||
getEncryptionTrustLevelForDeviceUseCase = getEncryptionTrustLevelForDeviceUseCase,
|
||||
checkIfSessionIsInactiveUseCase = checkIfSessionIsInactiveUseCase,
|
||||
parseDeviceUserAgentUseCase = parseDeviceUserAgentUseCase,
|
||||
getMatrixClientInfoUseCase = getMatrixClientInfoUseCase,
|
||||
)
|
||||
|
||||
@Before
|
||||
|
@ -80,19 +84,14 @@ class GetDeviceFullInfoUseCaseTest {
|
|||
fun `given current session and info for device when getting device info then the result is correct`() = runTest {
|
||||
// Given
|
||||
val currentSessionCrossSigningInfo = givenCurrentSessionCrossSigningInfo()
|
||||
val deviceInfo = DeviceInfo(
|
||||
lastSeenTs = A_TIMESTAMP,
|
||||
)
|
||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.myDevicesInfoWithIdLiveData = MutableLiveData(Optional(deviceInfo))
|
||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.myDevicesInfoWithIdLiveData.givenAsFlow()
|
||||
val cryptoDeviceInfo = CryptoDeviceInfo(deviceId = A_DEVICE_ID, userId = "")
|
||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.cryptoDeviceInfoWithIdLiveData = MutableLiveData(Optional(cryptoDeviceInfo))
|
||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.cryptoDeviceInfoWithIdLiveData.givenAsFlow()
|
||||
val deviceInfo = givenADeviceInfo()
|
||||
val cryptoDeviceInfo = givenACryptoDeviceInfo()
|
||||
val trustLevel = givenTrustLevel(currentSessionCrossSigningInfo, cryptoDeviceInfo)
|
||||
val isInactive = false
|
||||
val isCurrentDevice = true
|
||||
every { checkIfSessionIsInactiveUseCase.execute(any()) } returns isInactive
|
||||
every { parseDeviceUserAgentUseCase.execute(any()) } returns DeviceExtendedInfo(DeviceType.MOBILE)
|
||||
val matrixClientInfo = givenAMatrixClientInfo()
|
||||
|
||||
// When
|
||||
val deviceFullInfo = getDeviceFullInfoUseCase.execute(A_DEVICE_ID).firstOrNull()
|
||||
|
@ -104,14 +103,18 @@ class GetDeviceFullInfoUseCaseTest {
|
|||
roomEncryptionTrustLevel = trustLevel,
|
||||
isInactive = isInactive,
|
||||
isCurrentDevice = isCurrentDevice,
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE)
|
||||
deviceExtendedInfo = DeviceExtendedInfo(DeviceType.MOBILE),
|
||||
matrixClientInfo = matrixClientInfo,
|
||||
)
|
||||
verify { fakeActiveSessionHolder.instance.getSafeActiveSession() }
|
||||
verify { getCurrentSessionCrossSigningInfoUseCase.execute() }
|
||||
verify { getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo) }
|
||||
verify { fakeActiveSessionHolder.fakeSession.fakeCryptoService.getMyDevicesInfoLive(A_DEVICE_ID).asFlow() }
|
||||
verify { fakeActiveSessionHolder.fakeSession.fakeCryptoService.getLiveCryptoDeviceInfoWithId(A_DEVICE_ID).asFlow() }
|
||||
verify { checkIfSessionIsInactiveUseCase.execute(A_TIMESTAMP) }
|
||||
verify {
|
||||
fakeActiveSessionHolder.instance.getSafeActiveSession()
|
||||
getCurrentSessionCrossSigningInfoUseCase.execute()
|
||||
getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo)
|
||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.getMyDevicesInfoLive(A_DEVICE_ID).asFlow()
|
||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.getLiveCryptoDeviceInfoWithId(A_DEVICE_ID).asFlow()
|
||||
checkIfSessionIsInactiveUseCase.execute(A_TIMESTAMP)
|
||||
getMatrixClientInfoUseCase.execute(fakeActiveSessionHolder.fakeSession, A_DEVICE_ID)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -161,4 +164,27 @@ class GetDeviceFullInfoUseCaseTest {
|
|||
every { getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo) } returns trustLevel
|
||||
return trustLevel
|
||||
}
|
||||
|
||||
private fun givenADeviceInfo(): DeviceInfo {
|
||||
val deviceInfo = DeviceInfo(
|
||||
deviceId = A_DEVICE_ID,
|
||||
lastSeenTs = A_TIMESTAMP,
|
||||
)
|
||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.myDevicesInfoWithIdLiveData = MutableLiveData(Optional(deviceInfo))
|
||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.myDevicesInfoWithIdLiveData.givenAsFlow()
|
||||
return deviceInfo
|
||||
}
|
||||
|
||||
private fun givenACryptoDeviceInfo(): CryptoDeviceInfo {
|
||||
val cryptoDeviceInfo = CryptoDeviceInfo(deviceId = A_DEVICE_ID, userId = "")
|
||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.cryptoDeviceInfoWithIdLiveData = MutableLiveData(Optional(cryptoDeviceInfo))
|
||||
fakeActiveSessionHolder.fakeSession.fakeCryptoService.cryptoDeviceInfoWithIdLiveData.givenAsFlow()
|
||||
return cryptoDeviceInfo
|
||||
}
|
||||
|
||||
private fun givenAMatrixClientInfo(): MatrixClientInfoContent {
|
||||
val matrixClientInfo = mockk<MatrixClientInfoContent>()
|
||||
every { getMatrixClientInfoUseCase.execute(fakeActiveSessionHolder.fakeSession, A_DEVICE_ID) } returns matrixClientInfo
|
||||
return matrixClientInfo
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue