mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Merge pull request #7361 from vector-im/feature/mna/device-manager-unknown-verification-status
[Device management] Update the unknown verification status icon (PSG-824)
This commit is contained in:
commit
612d2e51e5
1
changelog.d/7327.wip
Normal file
1
changelog.d/7327.wip
Normal file
@ -0,0 +1 @@
|
||||
[Device management] Update the unknown verification status icon
|
@ -3254,10 +3254,12 @@
|
||||
<string name="a11y_device_manager_device_type_unknown">Unknown device type</string>
|
||||
<string name="device_manager_verification_status_verified">Verified session</string>
|
||||
<string name="device_manager_verification_status_unverified">Unverified session</string>
|
||||
<string name="device_manager_verification_status_unknown">Unknown verification status</string>
|
||||
<string name="device_manager_verification_status_detail_current_session_verified">Your current session is ready for secure messaging.</string>
|
||||
<string name="device_manager_verification_status_detail_other_session_verified">This session is ready for secure messaging.</string>
|
||||
<string name="device_manager_verification_status_detail_current_session_unverified">Verify your current session for enhanced secure messaging.</string>
|
||||
<string name="device_manager_verification_status_detail_other_session_unverified">Verify or sign out from this session for best security and reliability.</string>
|
||||
<string name="device_manager_verification_status_detail_other_session_unknown">Verify your current session to reveal this session\'s verification status.</string>
|
||||
<string name="device_manager_verify_session">Verify Session</string>
|
||||
<string name="device_manager_view_details">View Details</string>
|
||||
<string name="device_manager_other_sessions_view_all">View All (%1$d)</string>
|
||||
|
@ -146,6 +146,7 @@
|
||||
<color name="shield_color_gray">#91A1C0</color>
|
||||
<color name="shield_color_warning">#FF4B55</color>
|
||||
<color name="shield_color_warning_background">#0FFF4B55</color>
|
||||
<color name="shield_color_unknown">@color/palette_gray_200</color>
|
||||
|
||||
<!-- Badge Colors -->
|
||||
<attr name="vctr_badge_color_border" format="color" />
|
||||
|
@ -53,6 +53,8 @@ android {
|
||||
// "pm clear" command after each test invocation. This command ensures
|
||||
// that the app's state is completely cleared between tests.
|
||||
testInstrumentationRunnerArguments clearPackageData: 'true'
|
||||
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
}
|
||||
|
||||
testOptions {
|
||||
|
@ -45,8 +45,8 @@ class ShieldImageView @JvmOverloads constructor(
|
||||
RoomEncryptionTrustLevel.Default -> {
|
||||
contentDescription = context.getString(R.string.a11y_trust_level_default)
|
||||
setImageResource(
|
||||
if (borderLess) R.drawable.ic_shield_black_no_border
|
||||
else R.drawable.ic_shield_black
|
||||
if (borderLess) R.drawable.ic_shield_unknown_no_border
|
||||
else R.drawable.ic_shield_unknown
|
||||
)
|
||||
}
|
||||
RoomEncryptionTrustLevel.Warning -> {
|
||||
@ -137,7 +137,7 @@ class ShieldImageView @JvmOverloads constructor(
|
||||
@DrawableRes
|
||||
fun RoomEncryptionTrustLevel.toDrawableRes(): Int {
|
||||
return when (this) {
|
||||
RoomEncryptionTrustLevel.Default -> R.drawable.ic_shield_black
|
||||
RoomEncryptionTrustLevel.Default -> R.drawable.ic_shield_unknown
|
||||
RoomEncryptionTrustLevel.Warning -> R.drawable.ic_shield_warning
|
||||
RoomEncryptionTrustLevel.Trusted -> R.drawable.ic_shield_trusted
|
||||
RoomEncryptionTrustLevel.E2EWithUnsupportedAlgorithm -> R.drawable.ic_warning_badge
|
||||
|
@ -57,7 +57,7 @@ class GetDeviceFullInfoListUseCase @Inject constructor(
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
filterDevicesUseCase.execute(deviceFullInfoList, filterType, excludedDeviceIds)
|
||||
filterDevicesUseCase.execute(currentSessionCrossSigningInfo, deviceFullInfoList, filterType, excludedDeviceIds)
|
||||
}
|
||||
|
||||
deviceFullInfoFlow.distinctUntilChanged()
|
||||
|
@ -44,6 +44,7 @@ import im.vector.app.features.settings.devices.v2.list.SESSION_IS_MARKED_AS_INAC
|
||||
import im.vector.app.features.settings.devices.v2.list.SecurityRecommendationView
|
||||
import im.vector.app.features.settings.devices.v2.list.SecurityRecommendationViewState
|
||||
import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState
|
||||
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
@ -164,12 +165,11 @@ class VectorSettingsDevicesFragment :
|
||||
if (state.devices is Success) {
|
||||
val devices = state.devices()
|
||||
val currentDeviceId = state.currentSessionCrossSigningInfo.deviceId
|
||||
val currentDeviceInfo = devices?.firstOrNull {
|
||||
it.deviceInfo.deviceId == currentDeviceId
|
||||
}
|
||||
val currentDeviceInfo = devices?.firstOrNull { it.deviceInfo.deviceId == currentDeviceId }
|
||||
val isCurrentSessionVerified = currentDeviceInfo?.roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Trusted
|
||||
val otherDevices = devices?.filter { it.deviceInfo.deviceId != currentDeviceId }
|
||||
|
||||
renderSecurityRecommendations(state.inactiveSessionsCount, state.unverifiedSessionsCount)
|
||||
renderSecurityRecommendations(state.inactiveSessionsCount, state.unverifiedSessionsCount, isCurrentSessionVerified)
|
||||
renderCurrentDevice(currentDeviceInfo)
|
||||
renderOtherSessionsView(otherDevices)
|
||||
} else {
|
||||
@ -181,14 +181,21 @@ class VectorSettingsDevicesFragment :
|
||||
handleLoadingStatus(state.isLoading)
|
||||
}
|
||||
|
||||
private fun renderSecurityRecommendations(inactiveSessionsCount: Int, unverifiedSessionsCount: Int) {
|
||||
if (unverifiedSessionsCount == 0 && inactiveSessionsCount == 0) {
|
||||
private fun renderSecurityRecommendations(
|
||||
inactiveSessionsCount: Int,
|
||||
unverifiedSessionsCount: Int,
|
||||
isCurrentSessionVerified: Boolean,
|
||||
) {
|
||||
val isUnverifiedSectionVisible = unverifiedSessionsCount > 0 && isCurrentSessionVerified
|
||||
val isInactiveSectionVisible = inactiveSessionsCount > 0
|
||||
if (isUnverifiedSectionVisible.not() && isInactiveSectionVisible.not()) {
|
||||
hideSecurityRecommendations()
|
||||
} else {
|
||||
views.deviceListHeaderSectionSecurityRecommendations.isVisible = true
|
||||
views.deviceListSecurityRecommendationsDivider.isVisible = true
|
||||
views.deviceListUnverifiedSessionsRecommendation.isVisible = unverifiedSessionsCount > 0
|
||||
views.deviceListInactiveSessionsRecommendation.isVisible = inactiveSessionsCount > 0
|
||||
|
||||
views.deviceListUnverifiedSessionsRecommendation.isVisible = isUnverifiedSectionVisible
|
||||
views.deviceListInactiveSessionsRecommendation.isVisible = isInactiveSectionVisible
|
||||
val unverifiedSessionsViewState = SecurityRecommendationViewState(
|
||||
description = getString(R.string.device_manager_unverified_sessions_description),
|
||||
sessionsCount = unverifiedSessionsCount,
|
||||
@ -206,11 +213,19 @@ class VectorSettingsDevicesFragment :
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideUnverifiedSessionsRecommendation() {
|
||||
views.deviceListUnverifiedSessionsRecommendation.isVisible = false
|
||||
}
|
||||
|
||||
private fun hideInactiveSessionsRecommendation() {
|
||||
views.deviceListInactiveSessionsRecommendation.isVisible = false
|
||||
}
|
||||
|
||||
private fun hideSecurityRecommendations() {
|
||||
views.deviceListHeaderSectionSecurityRecommendations.isVisible = false
|
||||
views.deviceListUnverifiedSessionsRecommendation.isVisible = false
|
||||
views.deviceListInactiveSessionsRecommendation.isVisible = false
|
||||
views.deviceListSecurityRecommendationsDivider.isVisible = false
|
||||
hideUnverifiedSessionsRecommendation()
|
||||
hideInactiveSessionsRecommendation()
|
||||
}
|
||||
|
||||
private fun renderOtherSessionsView(otherDevices: List<DeviceFullInfo>?) {
|
||||
|
@ -17,22 +17,27 @@
|
||||
package im.vector.app.features.settings.devices.v2.filter
|
||||
|
||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||
import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
import javax.inject.Inject
|
||||
|
||||
class FilterDevicesUseCase @Inject constructor() {
|
||||
|
||||
fun execute(
|
||||
currentSessionCrossSigningInfo: CurrentSessionCrossSigningInfo,
|
||||
devices: List<DeviceFullInfo>,
|
||||
filterType: DeviceManagerFilterType,
|
||||
excludedDeviceIds: List<String> = emptyList(),
|
||||
): List<DeviceFullInfo> {
|
||||
val isCurrentSessionVerified = currentSessionCrossSigningInfo.isCrossSigningVerified.orFalse()
|
||||
return devices
|
||||
.filter {
|
||||
when (filterType) {
|
||||
DeviceManagerFilterType.ALL_SESSIONS -> true
|
||||
DeviceManagerFilterType.VERIFIED -> it.cryptoDeviceInfo?.trustLevel?.isCrossSigningVerified().orFalse()
|
||||
DeviceManagerFilterType.UNVERIFIED -> !it.cryptoDeviceInfo?.trustLevel?.isCrossSigningVerified().orFalse()
|
||||
// when current session is not verified, other session status cannot be trusted
|
||||
DeviceManagerFilterType.VERIFIED -> isCurrentSessionVerified && it.cryptoDeviceInfo?.trustLevel?.isCrossSigningVerified().orFalse()
|
||||
// when current session is not verified, other session status cannot be trusted
|
||||
DeviceManagerFilterType.UNVERIFIED -> isCurrentSessionVerified && !it.cryptoDeviceInfo?.trustLevel?.isCrossSigningVerified().orFalse()
|
||||
DeviceManagerFilterType.INACTIVE -> it.isInactive
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ class OtherSessionsController @Inject constructor(
|
||||
data.forEach { device ->
|
||||
val dateFormatKind = if (device.isInactive) DateFormatKind.TIMELINE_DAY_DIVIDER else DateFormatKind.DEFAULT_DATE_AND_TIME
|
||||
val formattedLastActivityDate = host.dateFormatter.format(device.deviceInfo.lastSeenTs, dateFormatKind)
|
||||
val description = calculateDescription(device, formattedLastActivityDate)
|
||||
val description = buildDescription(device, formattedLastActivityDate)
|
||||
val descriptionColor = if (device.isCurrentDevice) {
|
||||
host.colorProvider.getColorFromAttribute(R.attr.colorError)
|
||||
} else {
|
||||
@ -77,7 +77,7 @@ class OtherSessionsController @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateDescription(device: DeviceFullInfo, formattedLastActivityDate: String): String {
|
||||
private fun buildDescription(device: DeviceFullInfo, formattedLastActivityDate: String): String {
|
||||
return when {
|
||||
device.isInactive -> {
|
||||
stringProvider.getQuantityString(
|
||||
@ -93,6 +93,9 @@ class OtherSessionsController @Inject constructor(
|
||||
device.isCurrentDevice -> {
|
||||
stringProvider.getString(R.string.device_manager_other_sessions_description_unverified_current_session)
|
||||
}
|
||||
device.roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Default -> {
|
||||
stringProvider.getString(R.string.device_manager_session_last_activity, formattedLastActivityDate)
|
||||
}
|
||||
else -> {
|
||||
stringProvider.getString(R.string.device_manager_other_sessions_description_unverified, formattedLastActivityDate)
|
||||
}
|
||||
|
@ -90,10 +90,10 @@ class SessionInfoView @JvmOverloads constructor(
|
||||
isVerifyButtonVisible: Boolean,
|
||||
) {
|
||||
views.sessionInfoVerificationStatusImageView.render(encryptionTrustLevel)
|
||||
if (encryptionTrustLevel == RoomEncryptionTrustLevel.Trusted) {
|
||||
renderCrossSigningVerified(isCurrentSession)
|
||||
} else {
|
||||
renderCrossSigningUnverified(isCurrentSession, isVerifyButtonVisible)
|
||||
when {
|
||||
encryptionTrustLevel == RoomEncryptionTrustLevel.Trusted -> renderCrossSigningVerified(isCurrentSession)
|
||||
encryptionTrustLevel == RoomEncryptionTrustLevel.Default && !isCurrentSession -> renderCrossSigningUnknown()
|
||||
else -> renderCrossSigningUnverified(isCurrentSession, isVerifyButtonVisible)
|
||||
}
|
||||
if (hasLearnMoreLink) {
|
||||
appendLearnMoreToVerificationStatus()
|
||||
@ -142,6 +142,12 @@ class SessionInfoView @JvmOverloads constructor(
|
||||
views.sessionInfoVerifySessionButton.isVisible = isVerifyButtonVisible
|
||||
}
|
||||
|
||||
private fun renderCrossSigningUnknown() {
|
||||
views.sessionInfoVerificationStatusTextView.text = context.getString(R.string.device_manager_verification_status_unknown)
|
||||
views.sessionInfoVerificationStatusDetailTextView.text = context.getString(R.string.device_manager_verification_status_detail_other_session_unknown)
|
||||
views.sessionInfoVerifySessionButton.isVisible = false
|
||||
}
|
||||
|
||||
private fun renderDeviceInfo(sessionName: String, deviceType: DeviceType, stringProvider: StringProvider) {
|
||||
setDeviceTypeIconUseCase.execute(deviceType, views.sessionInfoDeviceTypeImageView, stringProvider)
|
||||
views.sessionInfoNameTextView.text = sessionName
|
||||
@ -155,34 +161,31 @@ class SessionInfoView @JvmOverloads constructor(
|
||||
drawableProvider: DrawableProvider,
|
||||
colorProvider: ColorProvider,
|
||||
) {
|
||||
deviceInfo.lastSeenTs
|
||||
?.takeIf { isLastSeenDetailsVisible }
|
||||
?.let { timestamp ->
|
||||
views.sessionInfoLastActivityTextView.isVisible = true
|
||||
views.sessionInfoLastActivityTextView.text = if (isInactive) {
|
||||
val formattedTs = dateFormatter.format(timestamp, DateFormatKind.TIMELINE_DAY_DIVIDER)
|
||||
context.resources.getQuantityString(
|
||||
R.plurals.device_manager_other_sessions_description_inactive,
|
||||
SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS,
|
||||
SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS,
|
||||
formattedTs
|
||||
)
|
||||
} else {
|
||||
val formattedTs = dateFormatter.format(timestamp, DateFormatKind.DEFAULT_DATE_AND_TIME)
|
||||
context.getString(R.string.device_manager_session_last_activity, formattedTs)
|
||||
}
|
||||
val drawable = if (isInactive) {
|
||||
val drawableColor = colorProvider.getColorFromAttribute(R.attr.vctr_content_secondary)
|
||||
drawableProvider.getDrawable(R.drawable.ic_inactive_sessions, drawableColor)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
views.sessionInfoLastActivityTextView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null)
|
||||
}
|
||||
?: run {
|
||||
views.sessionInfoLastActivityTextView.isGone = true
|
||||
}
|
||||
|
||||
if (deviceInfo.lastSeenTs != null && isLastSeenDetailsVisible) {
|
||||
val timestamp = deviceInfo.lastSeenTs
|
||||
views.sessionInfoLastActivityTextView.isVisible = true
|
||||
views.sessionInfoLastActivityTextView.text = if (isInactive) {
|
||||
val formattedTs = dateFormatter.format(timestamp, DateFormatKind.TIMELINE_DAY_DIVIDER)
|
||||
context.resources.getQuantityString(
|
||||
R.plurals.device_manager_other_sessions_description_inactive,
|
||||
SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS,
|
||||
SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS,
|
||||
formattedTs
|
||||
)
|
||||
} else {
|
||||
val formattedTs = dateFormatter.format(timestamp, DateFormatKind.DEFAULT_DATE_AND_TIME)
|
||||
context.getString(R.string.device_manager_session_last_activity, formattedTs)
|
||||
}
|
||||
val drawable = if (isInactive) {
|
||||
val drawableColor = colorProvider.getColorFromAttribute(R.attr.vctr_content_secondary)
|
||||
drawableProvider.getDrawable(R.drawable.ic_inactive_sessions, drawableColor)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
views.sessionInfoLastActivityTextView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null)
|
||||
} else {
|
||||
views.sessionInfoLastActivityTextView.isGone = true
|
||||
}
|
||||
views.sessionInfoLastIPAddressTextView.setTextOrHide(deviceInfo.lastSeenIp?.takeIf { isLastSeenDetailsVisible })
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,6 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
@ -42,7 +41,6 @@ import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.databinding.FragmentSessionOverviewBinding
|
||||
import im.vector.app.features.auth.ReAuthActivity
|
||||
import im.vector.app.features.crypto.recover.SetupMode
|
||||
import im.vector.app.features.settings.devices.v2.DeviceFullInfo
|
||||
import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState
|
||||
import im.vector.app.features.settings.devices.v2.more.SessionLearnMoreBottomSheet
|
||||
import im.vector.app.features.workers.signout.SignOutUiWorker
|
||||
@ -181,11 +179,6 @@ class SessionOverviewFragment :
|
||||
updateSessionInfo(state)
|
||||
updateLoading(state.isLoading)
|
||||
updatePushNotificationToggle(state.deviceId, state.pushers.invoke().orEmpty())
|
||||
if (state.deviceInfo is Success) {
|
||||
renderSessionInfo(state.isCurrentSessionTrusted, state.deviceInfo.invoke())
|
||||
} else {
|
||||
hideSessionInfo()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateToolbar(viewState: SessionOverviewViewState) {
|
||||
@ -214,7 +207,7 @@ class SessionOverviewFragment :
|
||||
deviceFullInfo = deviceInfo,
|
||||
isVerifyButtonVisible = isCurrentSession || viewState.isCurrentSessionTrusted,
|
||||
isDetailsButtonVisible = false,
|
||||
isLearnMoreLinkVisible = true,
|
||||
isLearnMoreLinkVisible = deviceInfo.roomEncryptionTrustLevel != RoomEncryptionTrustLevel.Default,
|
||||
isLastSeenDetailsVisible = !isCurrentSession,
|
||||
)
|
||||
views.sessionOverviewInfo.render(infoViewState, dateFormatter, drawableProvider, colorProvider, stringProvider)
|
||||
@ -243,18 +236,6 @@ class SessionOverviewFragment :
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderSessionInfo(isCurrentSession: Boolean, deviceFullInfo: DeviceFullInfo) {
|
||||
views.sessionOverviewInfo.isVisible = true
|
||||
val viewState = SessionInfoViewState(
|
||||
isCurrentSession = isCurrentSession,
|
||||
deviceFullInfo = deviceFullInfo,
|
||||
isDetailsButtonVisible = false,
|
||||
isLearnMoreLinkVisible = true,
|
||||
isLastSeenDetailsVisible = true,
|
||||
)
|
||||
views.sessionOverviewInfo.render(viewState, dateFormatter, drawableProvider, colorProvider, stringProvider)
|
||||
}
|
||||
|
||||
private fun updateLoading(isLoading: Boolean) {
|
||||
if (isLoading) {
|
||||
showLoading(null)
|
||||
@ -313,8 +294,4 @@ class SessionOverviewFragment :
|
||||
)
|
||||
SessionLearnMoreBottomSheet.show(childFragmentManager, args)
|
||||
}
|
||||
|
||||
private fun hideSessionInfo() {
|
||||
views.sessionOverviewInfo.isGone = true
|
||||
}
|
||||
}
|
||||
|
20
vector/src/main/res/drawable/ic_shield_unknown.xml
Normal file
20
vector/src/main/res/drawable/ic_shield_unknown.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/shield_color_unknown"
|
||||
android:pathData="M12.008,23.487C12.005,23.487 12.002,23.488 12,23.489C11.998,23.488 11.995,23.487 11.992,23.487C11.92,23.471 11.813,23.445 11.675,23.409C11.399,23.337 11.002,23.223 10.523,23.058C9.565,22.725 8.292,22.186 7.022,21.361C4.49,19.715 2,16.954 2,12.405V3.45L12,0.521L22,3.45V12.405C22,16.954 19.51,19.715 16.978,21.361C15.708,22.186 14.435,22.725 13.477,23.058C12.998,23.223 12.601,23.337 12.325,23.409C12.187,23.445 12.08,23.471 12.008,23.487Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#ffffff" />
|
||||
<path
|
||||
android:fillColor="@color/shield_color_unknown"
|
||||
android:pathData="M12.008,23.487C12.005,23.487 12.002,23.488 12,23.489C11.998,23.488 11.995,23.487 11.992,23.487C11.92,23.471 11.813,23.445 11.675,23.409C11.399,23.337 11.002,23.223 10.523,23.058C9.565,22.725 8.292,22.186 7.022,21.361C4.49,19.715 2,16.954 2,12.405V3.45L12,0.521L22,3.45V12.405C22,16.954 19.51,19.715 16.978,21.361C15.708,22.186 14.435,22.725 13.477,23.058C12.998,23.223 12.601,23.337 12.325,23.409C12.187,23.445 12.08,23.471 12.008,23.487Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#ffffff" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M12.003,16.5C12.577,16.5 13.043,16.035 13.043,15.46C13.043,14.887 12.577,14.421 12.003,14.421C11.429,14.421 10.964,14.887 10.964,15.46C10.964,16.035 11.429,16.5 12.003,16.5ZM10.559,9.823C10.559,9.023 11.208,8.379 12.003,8.379C12.795,8.379 13.447,9.031 13.447,9.823C13.447,10.19 13.29,10.321 12.671,10.748C12.398,10.937 12.022,11.2 11.729,11.586C11.416,11.999 11.223,12.513 11.223,13.168H12.783C12.783,12.847 12.868,12.665 12.971,12.528C13.096,12.364 13.276,12.226 13.558,12.031C13.587,12.01 13.618,11.989 13.651,11.967C14.162,11.619 15.006,11.045 15.006,9.823C15.006,8.17 13.656,6.82 12.003,6.82C10.352,6.82 9,8.157 9,9.823H10.559Z" />
|
||||
</vector>
|
18
vector/src/main/res/drawable/ic_shield_unknown_no_border.xml
Normal file
18
vector/src/main/res/drawable/ic_shield_unknown_no_border.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/shield_color_unknown"
|
||||
android:pathData="M12.008,23.487C12.005,23.487 12.002,23.488 12,23.489C11.998,23.488 11.995,23.487 11.992,23.487C11.92,23.471 11.813,23.445 11.675,23.409C11.399,23.337 11.002,23.223 10.523,23.058C9.565,22.725 8.292,22.186 7.022,21.361C4.49,19.715 2,16.954 2,12.405V3.45L12,0.521L22,3.45V12.405C22,16.954 19.51,19.715 16.978,21.361C15.708,22.186 14.435,22.725 13.477,23.058C12.998,23.223 12.601,23.337 12.325,23.409C12.187,23.445 12.08,23.471 12.008,23.487Z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#ffffff" />
|
||||
<path
|
||||
android:fillColor="@color/shield_color_unknown"
|
||||
android:pathData="M1.5,12.405V3.075L12,0L22.5,3.075V12.405C22.5,21.945 12,24 12,24C12,24 1.5,21.945 1.5,12.405Z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M12.003,16.5C12.577,16.5 13.043,16.035 13.043,15.46C13.043,14.887 12.577,14.421 12.003,14.421C11.429,14.421 10.964,14.887 10.964,15.46C10.964,16.035 11.429,16.5 12.003,16.5ZM10.559,9.823C10.559,9.023 11.208,8.379 12.003,8.379C12.795,8.379 13.447,9.031 13.447,9.823C13.447,10.19 13.29,10.321 12.671,10.748C12.398,10.937 12.022,11.2 11.729,11.586C11.416,11.999 11.223,12.513 11.223,13.168H12.783C12.783,12.847 12.868,12.665 12.971,12.528C13.096,12.364 13.276,12.226 13.558,12.031C13.587,12.01 13.618,11.989 13.651,11.967C14.162,11.619 15.006,11.045 15.006,9.823C15.006,8.17 13.656,6.82 12.003,6.82C10.352,6.82 9,8.157 9,9.823H10.559Z" />
|
||||
</vector>
|
@ -144,10 +144,11 @@ class GetDeviceFullInfoListUseCaseTest {
|
||||
matrixClientInfo = matrixClientInfo3,
|
||||
)
|
||||
val expectedResult = listOf(expectedResult3, expectedResult2, expectedResult1)
|
||||
every { filterDevicesUseCase.execute(any(), any()) } returns expectedResult
|
||||
every { filterDevicesUseCase.execute(any(), any(), any()) } returns expectedResult
|
||||
val filterType = DeviceManagerFilterType.ALL_SESSIONS
|
||||
|
||||
// When
|
||||
val result = getDeviceFullInfoListUseCase.execute(DeviceManagerFilterType.ALL_SESSIONS, excludeCurrentDevice = false)
|
||||
val result = getDeviceFullInfoListUseCase.execute(filterType, excludeCurrentDevice = false)
|
||||
.test(this)
|
||||
|
||||
// Then
|
||||
@ -166,6 +167,7 @@ class GetDeviceFullInfoListUseCaseTest {
|
||||
getMatrixClientInfoUseCase.execute(fakeActiveSessionHolder.fakeSession, A_DEVICE_ID_1)
|
||||
getMatrixClientInfoUseCase.execute(fakeActiveSessionHolder.fakeSession, A_DEVICE_ID_2)
|
||||
getMatrixClientInfoUseCase.execute(fakeActiveSessionHolder.fakeSession, A_DEVICE_ID_3)
|
||||
filterDevicesUseCase.execute(currentSessionCrossSigningInfo, expectedResult, filterType, emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ 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 im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.amshove.kluent.shouldContainAll
|
||||
import org.junit.Test
|
||||
@ -94,32 +95,58 @@ class FilterDevicesUseCaseTest {
|
||||
|
||||
@Test
|
||||
fun `given a device list when filter type is ALL_SESSIONS then returns the same list`() {
|
||||
val filteredDeviceList = filterDevicesUseCase.execute(devices, DeviceManagerFilterType.ALL_SESSIONS, emptyList())
|
||||
val currentSessionCrossSigningInfo = givenCurrentSessionVerified(true)
|
||||
val filteredDeviceList = filterDevicesUseCase.execute(currentSessionCrossSigningInfo, devices, DeviceManagerFilterType.ALL_SESSIONS, emptyList())
|
||||
|
||||
filteredDeviceList.size shouldBeEqualTo devices.size
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a device list when filter type is VERIFIED then returns only verified devices`() {
|
||||
val filteredDeviceList = filterDevicesUseCase.execute(devices, DeviceManagerFilterType.VERIFIED, emptyList())
|
||||
fun `given a device list and current session is verified when filter type is VERIFIED then returns only verified devices`() {
|
||||
val currentSessionCrossSigningInfo = givenCurrentSessionVerified(true)
|
||||
val filteredDeviceList = filterDevicesUseCase.execute(currentSessionCrossSigningInfo, devices, DeviceManagerFilterType.VERIFIED, emptyList())
|
||||
|
||||
filteredDeviceList.size shouldBeEqualTo 2
|
||||
filteredDeviceList shouldContainAll listOf(activeVerifiedDevice, inactiveVerifiedDevice)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a device list when filter type is UNVERIFIED then returns only unverified devices`() {
|
||||
val filteredDeviceList = filterDevicesUseCase.execute(devices, DeviceManagerFilterType.UNVERIFIED, emptyList())
|
||||
fun `given a device list and current session is unverified when filter type is VERIFIED then returns empty list of devices`() {
|
||||
val currentSessionCrossSigningInfo = givenCurrentSessionVerified(false)
|
||||
val filteredDeviceList = filterDevicesUseCase.execute(currentSessionCrossSigningInfo, devices, DeviceManagerFilterType.VERIFIED, emptyList())
|
||||
|
||||
filteredDeviceList.size shouldBeEqualTo 0
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a device list and current session is verified when filter type is UNVERIFIED then returns only unverified devices`() {
|
||||
val currentSessionCrossSigningInfo = givenCurrentSessionVerified(true)
|
||||
val filteredDeviceList = filterDevicesUseCase.execute(currentSessionCrossSigningInfo, devices, DeviceManagerFilterType.UNVERIFIED, emptyList())
|
||||
|
||||
filteredDeviceList.size shouldBeEqualTo 2
|
||||
filteredDeviceList shouldContainAll listOf(activeUnverifiedDevice, inactiveUnverifiedDevice)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a device list and current session is unverified when filter type is UNVERIFIED then returns empty list of devices`() {
|
||||
val currentSessionCrossSigningInfo = givenCurrentSessionVerified(false)
|
||||
val filteredDeviceList = filterDevicesUseCase.execute(currentSessionCrossSigningInfo, devices, DeviceManagerFilterType.UNVERIFIED, emptyList())
|
||||
|
||||
filteredDeviceList.size shouldBeEqualTo 0
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given a device list when filter type is INACTIVE then returns only inactive devices`() {
|
||||
val filteredDeviceList = filterDevicesUseCase.execute(devices, DeviceManagerFilterType.INACTIVE, emptyList())
|
||||
val currentSessionCrossSigningInfo = givenCurrentSessionVerified(true)
|
||||
val filteredDeviceList = filterDevicesUseCase.execute(currentSessionCrossSigningInfo, devices, DeviceManagerFilterType.INACTIVE, emptyList())
|
||||
|
||||
filteredDeviceList.size shouldBeEqualTo 2
|
||||
filteredDeviceList shouldContainAll listOf(inactiveVerifiedDevice, inactiveUnverifiedDevice)
|
||||
}
|
||||
|
||||
private fun givenCurrentSessionVerified(isVerified: Boolean): CurrentSessionCrossSigningInfo = CurrentSessionCrossSigningInfo(
|
||||
isCrossSigningVerified = isVerified,
|
||||
isCrossSigningInitialized = true,
|
||||
deviceId = ""
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user