From 8749e49e807330e18e4fa27218d80c335a841baa Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 3 Jan 2020 14:54:10 +0100 Subject: [PATCH] Basic Incoming request toast + cleaning --- .../crypto/sas/SasVerificationService.kt | 1 + .../tasks/RoomVerificationUpdateTask.kt | 3 + .../DefaultSasVerificationService.kt | 27 +- .../PendingVerificationRequest.kt | 4 +- vector/src/main/AndroidManifest.xml | 3 - .../im/vector/riotx/core/di/FragmentModule.kt | 25 -- .../vector/riotx/core/di/ViewModelModule.kt | 6 - .../riotx/core/platform/VectorBaseActivity.kt | 10 +- .../crypto/keysrequest/KeyRequestHandler.kt | 29 +-- .../IncomingVerificationRequestHandler.kt | 135 +++++++--- .../verification/SASVerificationActivity.kt | 245 ------------------ .../SASVerificationIncomingFragment.kt | 100 ------- .../SASVerificationShortCodeFragment.kt | 170 ------------ .../SASVerificationStartFragment.kt | 120 --------- .../SASVerificationVerifiedFragment.kt | 41 --- .../verification/SasVerificationViewModel.kt | 153 ----------- .../home/room/detail/RoomDetailAction.kt | 2 +- .../home/room/detail/RoomDetailActivity.kt | 2 +- .../home/room/detail/RoomDetailFragment.kt | 12 + .../home/room/detail/RoomDetailViewModel.kt | 13 + .../riotx/features/popup/PopupAlertManager.kt | 21 +- ...fragment_sas_verification_display_code.xml | 132 ---------- ...ment_sas_verification_incoming_request.xml | 132 ---------- .../fragment_sas_verification_start.xml | 89 ------- .../fragment_sas_verification_verified.xml | 69 ----- 25 files changed, 189 insertions(+), 1355 deletions(-) delete mode 100644 vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationActivity.kt delete mode 100644 vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationIncomingFragment.kt delete mode 100644 vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationShortCodeFragment.kt delete mode 100644 vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationStartFragment.kt delete mode 100644 vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationVerifiedFragment.kt delete mode 100644 vector/src/main/java/im/vector/riotx/features/crypto/verification/SasVerificationViewModel.kt delete mode 100644 vector/src/main/res/layout/fragment_sas_verification_display_code.xml delete mode 100644 vector/src/main/res/layout/fragment_sas_verification_incoming_request.xml delete mode 100644 vector/src/main/res/layout/fragment_sas_verification_start.xml delete mode 100644 vector/src/main/res/layout/fragment_sas_verification_verified.xml diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationService.kt index c2a847dd0b..3130d857de 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationService.kt @@ -44,6 +44,7 @@ interface SasVerificationService { fun getExistingVerificationRequest(otherUser: String, tid: String?): PendingVerificationRequest? + fun getExistingVerificationRequestInRoom(roomId: String, tid: String?): PendingVerificationRequest? /** * Shortcut for KeyVerificationStart.VERIF_METHOD_SAS * @see beginKeyVerification diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/RoomVerificationUpdateTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/RoomVerificationUpdateTask.kt index 2167940aaa..c285f16ee3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/RoomVerificationUpdateTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/tasks/RoomVerificationUpdateTask.kt @@ -104,6 +104,7 @@ internal class DefaultRoomVerificationUpdateTask @Inject constructor( // The verification is started from another device Timber.v("## SAS Verification live observer: Transaction started by other device tid:${it.transactionID} ") it.transactionID?.let { txId -> transactionsHandledByOtherDevice.add(txId) } + params.sasVerificationService.onRoomRequestHandledByOtherDevice(event) } } } else if (EventType.KEY_VERIFICATION_READY == event.type) { @@ -112,11 +113,13 @@ internal class DefaultRoomVerificationUpdateTask @Inject constructor( // The verification is started from another device Timber.v("## SAS Verification live observer: Transaction started by other device tid:${it.transactionID} ") it.transactionID?.let { txId -> transactionsHandledByOtherDevice.add(txId) } + params.sasVerificationService.onRoomRequestHandledByOtherDevice(event) } } } else if (EventType.KEY_VERIFICATION_CANCEL == event.type || EventType.KEY_VERIFICATION_DONE == event.type) { event.getClearContent().toModel()?.relatesTo?.eventId?.let { transactionsHandledByOtherDevice.remove(it) + params.sasVerificationService.onRoomRequestHandledByOtherDevice(event) } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt index f5075cbb23..d4cced50ea 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultSasVerificationService.kt @@ -216,7 +216,20 @@ internal class DefaultSasVerificationService @Inject constructor( } } - fun onRoomRequestReceived(event: Event) { + fun onRoomRequestHandledByOtherDevice(event: Event) { + val requestInfo = event.getClearContent().toModel() + ?: return + val requestId = requestInfo.relatesTo?.eventId ?: return + getExistingVerificationRequestInRoom(event.roomId ?: "", requestId)?.let { + updatePendingRequest( + it.copy( + handledByOtherSession = true + ) + ) + } + } + + suspend fun onRoomRequestReceived(event: Event) { Timber.v("## SAS Verification request from ${event.senderId} in room ${event.roomId}") val requestInfo = event.getClearContent().toModel() ?: return @@ -245,6 +258,7 @@ internal class DefaultSasVerificationService @Inject constructor( ageLocalTs = event.ageLocalTs ?: System.currentTimeMillis(), isIncoming = true, otherUserId = senderId, // requestInfo.toUserId, + roomId = event.roomId, transactionId = event.eventId, requestInfo = requestInfo ) @@ -647,6 +661,16 @@ internal class DefaultSasVerificationService @Inject constructor( } } + override fun getExistingVerificationRequestInRoom(roomId: String, tid: String?): PendingVerificationRequest? { + synchronized(lock = pendingRequests) { + return tid?.let { tid -> + pendingRequests.flatMap { entry -> + entry.value.filter { it.roomId == roomId && it.transactionId == tid } + }.firstOrNull() + } + } + } + private fun getExistingTransactionsForUser(otherUser: String): Collection? { synchronized(txMap) { return txMap[otherUser]?.values @@ -723,6 +747,7 @@ internal class DefaultSasVerificationService @Inject constructor( val verificationRequest = PendingVerificationRequest( ageLocalTs = System.currentTimeMillis(), isIncoming = false, + roomId = roomId, localID = localID, otherUserId = userId ) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/PendingVerificationRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/PendingVerificationRequest.kt index c416bd3be3..2471062d69 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/PendingVerificationRequest.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/PendingVerificationRequest.kt @@ -27,11 +27,13 @@ data class PendingVerificationRequest( val isIncoming: Boolean = false, val localID: String = UUID.randomUUID().toString(), val otherUserId: String, + val roomId: String?, val transactionId: String? = null, val requestInfo: MessageVerificationRequestContent? = null, val readyInfo: VerificationInfoReady? = null, val cancelConclusion: CancelCode? = null, - val isSuccessful : Boolean = false + val isSuccessful : Boolean = false, + val handledByOtherSession : Boolean = false ) { diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index a0d4402767..c6e4b51c44 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -47,9 +47,6 @@ android:label="@string/title_activity_settings" android:windowSoftInputMode="adjustResize" /> - diff --git a/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt index 6855631aa3..3c4c1bd547 100644 --- a/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt +++ b/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt @@ -234,31 +234,6 @@ interface FragmentModule { @FragmentKey(VectorSettingsIgnoredUsersFragment::class) fun bindVectorSettingsIgnoredUsersFragment(fragment: VectorSettingsIgnoredUsersFragment): Fragment - @Binds - @IntoMap - @FragmentKey(VectorSettingsDevicesFragment::class) - fun bindVectorSettingsDevicesFragment(fragment: VectorSettingsDevicesFragment): Fragment - - @Binds - @IntoMap - @FragmentKey(SASVerificationIncomingFragment::class) - fun bindSASVerificationIncomingFragment(fragment: SASVerificationIncomingFragment): Fragment - - @Binds - @IntoMap - @FragmentKey(SASVerificationShortCodeFragment::class) - fun bindSASVerificationShortCodeFragment(fragment: SASVerificationShortCodeFragment): Fragment - - @Binds - @IntoMap - @FragmentKey(SASVerificationVerifiedFragment::class) - fun bindSASVerificationVerifiedFragment(fragment: SASVerificationVerifiedFragment): Fragment - - @Binds - @IntoMap - @FragmentKey(SASVerificationStartFragment::class) - fun bindSASVerificationStartFragment(fragment: SASVerificationStartFragment): Fragment - @Binds @IntoMap @FragmentKey(PublicRoomsFragment::class) diff --git a/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt b/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt index 5d4288f4b8..4bb0adb9f0 100644 --- a/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt +++ b/vector/src/main/java/im/vector/riotx/core/di/ViewModelModule.kt @@ -27,7 +27,6 @@ import im.vector.riotx.features.crypto.keysbackup.restore.KeysBackupRestoreFromK import im.vector.riotx.features.crypto.keysbackup.restore.KeysBackupRestoreFromPassphraseViewModel import im.vector.riotx.features.crypto.keysbackup.restore.KeysBackupRestoreSharedViewModel import im.vector.riotx.features.crypto.keysbackup.setup.KeysBackupSetupSharedViewModel -import im.vector.riotx.features.crypto.verification.SasVerificationViewModel import im.vector.riotx.features.home.HomeSharedActionViewModel import im.vector.riotx.features.home.room.detail.RoomDetailSharedActionViewModel import im.vector.riotx.features.home.room.detail.timeline.action.MessageSharedActionViewModel @@ -61,11 +60,6 @@ interface ViewModelModule { @ViewModelKey(EmojiChooserViewModel::class) fun bindEmojiChooserViewModel(viewModel: EmojiChooserViewModel): ViewModel - @Binds - @IntoMap - @ViewModelKey(SasVerificationViewModel::class) - fun bindSasVerificationViewModel(viewModel: SasVerificationViewModel): ViewModel - @Binds @IntoMap @ViewModelKey(KeysBackupRestoreFromKeyViewModel::class) diff --git a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt index 5c73fc97da..19112f2326 100644 --- a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt @@ -101,10 +101,12 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { private lateinit var configurationViewModel: ConfigurationViewModel private lateinit var sessionListener: SessionListener protected lateinit var bugReporter: BugReporter - lateinit var rageShake: RageShake + private lateinit var rageShake: RageShake + + lateinit var navigator: Navigator private set - protected lateinit var navigator: Navigator private lateinit var fragmentFactory: FragmentFactory + private lateinit var activeSessionHolder: ActiveSessionHolder private lateinit var vectorPreferences: VectorPreferences @@ -210,8 +212,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector { handleInvalidToken(globalError) is GlobalError.ConsentNotGivenError -> consentNotGivenHelper.displayDialog(globalError.consentUri, - activeSessionHolder.getActiveSession().sessionParams.homeServerConnectionConfig.homeServerUri.host - ?: "") + activeSessionHolder.getActiveSession().sessionParams.homeServerConnectionConfig.homeServerUri.host + ?: "") } } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt index f5db16c8ee..1af7d2fbd1 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysrequest/KeyRequestHandler.kt @@ -33,13 +33,11 @@ import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse import im.vector.riotx.R -import im.vector.riotx.features.crypto.verification.SASVerificationActivity import im.vector.riotx.features.popup.PopupAlertManager import timber.log.Timber import java.text.DateFormat import java.text.SimpleDateFormat -import java.util.Locale -import java.util.Date +import java.util.* import javax.inject.Inject import javax.inject.Singleton import kotlin.collections.ArrayList @@ -195,18 +193,19 @@ class KeyRequestHandler @Inject constructor(private val context: Context) denyAllRequests(mappingKey) } - alert.addButton( - context.getString(R.string.start_verification_short_label), - Runnable { - alert.weakCurrentActivity?.get()?.let { - val intent = SASVerificationActivity.outgoingIntent(it, - session?.myUserId ?: "", - userId, deviceId) - it.startActivity(intent) - } - }, - false - ) + // TODO send to the new profile page +// alert.addButton( +// context.getString(R.string.start_verification_short_label), +// Runnable { +// alert.weakCurrentActivity?.get()?.let { +// val intent = SASVerificationActivity.outgoingIntent(it, +// session?.myUserId ?: "", +// userId, deviceId) +// it.startActivity(intent) +// } +// }, +// false +// ) alert.addButton(context.getString(R.string.share_without_verifying_short_label), Runnable { shareAllSessions(mappingKey) diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt index 22ccec534a..b59e2d3f8c 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/IncomingVerificationRequestHandler.kt @@ -20,8 +20,13 @@ import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.crypto.sas.SasVerificationService import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTransaction import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState +import im.vector.matrix.android.internal.crypto.verification.PendingVerificationRequest import im.vector.riotx.R +import im.vector.riotx.core.platform.VectorBaseActivity +import im.vector.riotx.features.home.room.detail.RoomDetailActivity +import im.vector.riotx.features.home.room.detail.RoomDetailArgs import im.vector.riotx.features.popup.PopupAlertManager +import im.vector.riotx.features.themes.ThemeUtils import javax.inject.Inject import javax.inject.Singleton @@ -48,46 +53,46 @@ class IncomingVerificationRequestHandler @Inject constructor(private val context override fun transactionUpdated(tx: SasVerificationTransaction) { when (tx.state) { SasVerificationTxState.OnStarted -> { - // Add a notification for every incoming request - val name = session?.getUser(tx.otherUserId)?.displayName - ?: tx.otherUserId - - val alert = PopupAlertManager.VectorAlert( - "kvr_${tx.transactionId}", - context.getString(R.string.sas_incoming_request_notif_title), - context.getString(R.string.sas_incoming_request_notif_content, name), - R.drawable.shield) - .apply { - contentAction = Runnable { - val intent = SASVerificationActivity.incomingIntent(context, - session?.myUserId ?: "", - tx.otherUserId, - tx.transactionId) - weakCurrentActivity?.get()?.startActivity(intent) - } - dismissedAction = Runnable { - tx.cancel() - } - addButton( - context.getString(R.string.ignore), - Runnable { - tx.cancel() - } - ) - addButton( - context.getString(R.string.action_open), - Runnable { - val intent = SASVerificationActivity.incomingIntent(context, - session?.myUserId ?: "", - tx.otherUserId, - tx.transactionId) - weakCurrentActivity?.get()?.startActivity(intent) - } - ) - // 10mn expiration - expirationTimestamp = System.currentTimeMillis() + (10 * 60 * 1000L) - } - PopupAlertManager.postVectorAlert(alert) +// // Add a notification for every incoming request +// val name = session?.getUser(tx.otherUserId)?.displayName +// ?: tx.otherUserId +// +// val alert = PopupAlertManager.VectorAlert( +// "kvr_${tx.transactionId}", +// context.getString(R.string.sas_incoming_request_notif_title), +// context.getString(R.string.sas_incoming_request_notif_content, name), +// R.drawable.shield) +// .apply { +// contentAction = Runnable { +// val intent = SASVerificationActivity.incomingIntent(context, +// session?.myUserId ?: "", +// tx.otherUserId, +// tx.transactionId) +// weakCurrentActivity?.get()?.startActivity(intent) +// } +// dismissedAction = Runnable { +// tx.cancel() +// } +// addButton( +// context.getString(R.string.ignore), +// Runnable { +// tx.cancel() +// } +// ) +// addButton( +// context.getString(R.string.action_open), +// Runnable { +// val intent = SASVerificationActivity.incomingIntent(context, +// session?.myUserId ?: "", +// tx.otherUserId, +// tx.transactionId) +// weakCurrentActivity?.get()?.startActivity(intent) +// } +// ) +// // 10mn expiration +// expirationTimestamp = System.currentTimeMillis() + (10 * 60 * 1000L) +// } +// PopupAlertManager.postVectorAlert(alert) } SasVerificationTxState.Cancelled, SasVerificationTxState.OnCancelled, @@ -101,4 +106,54 @@ class IncomingVerificationRequestHandler @Inject constructor(private val context override fun markedAsManuallyVerified(userId: String, deviceId: String) { } + + override fun verificationRequestCreated(pr: PendingVerificationRequest) { + // For incoming request we should prompt (if not in activity where this request apply) + if (pr.isIncoming) { + val name = session?.getUser(pr.otherUserId)?.displayName + ?: pr.otherUserId + + val alert = PopupAlertManager.VectorAlert( + uniqueIdForVerificationRequest(pr), + context.getString(R.string.sas_incoming_request_notif_title), + "$name(${pr.otherUserId})", + R.drawable.ic_shield_black, + shouldBeDisplayedIn = { activity -> + if (activity is RoomDetailActivity) { + activity.intent?.extras?.getParcelable(RoomDetailActivity.EXTRA_ROOM_DETAIL_ARGS)?.let { + it.roomId != pr.roomId + } ?: true + } else true + }) + .apply { + contentAction = Runnable { + (weakCurrentActivity?.get() as? VectorBaseActivity)?.let { + it.navigator.openRoom(it, pr.roomId ?: "", pr.transactionId) + } + } + dismissedAction = Runnable { + session?.getSasVerificationService()?.declineVerificationRequestInDMs(pr.otherUserId, + pr.requestInfo?.fromDevice ?: "", + pr.transactionId ?: "", + pr.roomId ?: "" + ) + } + colorInt = ThemeUtils.getColor(context, R.attr.vctr_notice_secondary) + // 5mn expiration + expirationTimestamp = System.currentTimeMillis() + (5 * 60 * 1000L) + } + PopupAlertManager.postVectorAlert(alert) + } + } + + override fun verificationRequestUpdated(pr: PendingVerificationRequest) { + // If an incoming request is readied (by another device?) we should discard the alert + if (pr.isIncoming && (pr.isReady || pr.handledByOtherSession)) { + PopupAlertManager.cancelAlert(uniqueIdForVerificationRequest(pr)) + } + super.verificationRequestUpdated(pr) + } + + private fun uniqueIdForVerificationRequest(pr: PendingVerificationRequest) = + "verificationRequest_${pr.transactionId}" } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationActivity.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationActivity.kt deleted file mode 100644 index 222891eb3d..0000000000 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationActivity.kt +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright 2019 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.riotx.features.crypto.verification - -import android.app.Activity -import android.content.Context -import android.content.Intent -import android.view.MenuItem -import androidx.appcompat.app.AlertDialog -import androidx.lifecycle.Observer -import im.vector.matrix.android.api.session.crypto.sas.CancelCode -import im.vector.matrix.android.api.session.crypto.sas.IncomingSasVerificationTransaction -import im.vector.matrix.android.api.session.crypto.sas.OutgoingSasVerificationRequest -import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState -import im.vector.riotx.R -import im.vector.riotx.core.extensions.commitTransaction -import im.vector.riotx.core.extensions.observeEvent -import im.vector.riotx.core.platform.SimpleFragmentActivity -import im.vector.riotx.core.platform.WaitingViewData - -// TODO Deprecated("replaced by bottomsheet UX") -class SASVerificationActivity : SimpleFragmentActivity() { - - companion object { - - private const val EXTRA_MATRIX_ID = "EXTRA_MATRIX_ID" - private const val EXTRA_TRANSACTION_ID = "EXTRA_TRANSACTION_ID" - private const val EXTRA_OTHER_USER_ID = "EXTRA_OTHER_USER_ID" - private const val EXTRA_OTHER_DEVICE_ID = "EXTRA_OTHER_DEVICE_ID" - private const val EXTRA_IS_INCOMING = "EXTRA_IS_INCOMING" - - /* ========================================================================================== - * INPUT - * ========================================================================================== */ - - fun incomingIntent(context: Context, matrixID: String, otherUserId: String, transactionID: String): Intent { - val intent = Intent(context, SASVerificationActivity::class.java) - intent.putExtra(EXTRA_MATRIX_ID, matrixID) - intent.putExtra(EXTRA_TRANSACTION_ID, transactionID) - intent.putExtra(EXTRA_OTHER_USER_ID, otherUserId) - intent.putExtra(EXTRA_IS_INCOMING, true) - return intent - } - - fun outgoingIntent(context: Context, matrixID: String, otherUserId: String, otherDeviceId: String): Intent { - val intent = Intent(context, SASVerificationActivity::class.java) - intent.putExtra(EXTRA_MATRIX_ID, matrixID) - intent.putExtra(EXTRA_OTHER_DEVICE_ID, otherDeviceId) - intent.putExtra(EXTRA_OTHER_USER_ID, otherUserId) - intent.putExtra(EXTRA_IS_INCOMING, false) - return intent - } - - /* ========================================================================================== - * OUTPUT - * ========================================================================================== */ - - fun getOtherUserId(intent: Intent?): String? { - return intent?.getStringExtra(EXTRA_OTHER_USER_ID) - } - - fun getOtherDeviceId(intent: Intent?): String? { - return intent?.getStringExtra(EXTRA_OTHER_DEVICE_ID) - } - } - - override fun getTitleRes() = R.string.title_activity_verify_device - - private lateinit var viewModel: SasVerificationViewModel - - override fun initUiAndData() { - super.initUiAndData() - viewModel = viewModelProvider.get(SasVerificationViewModel::class.java) - val transactionID: String? = intent.getStringExtra(EXTRA_TRANSACTION_ID) - - if (isFirstCreation()) { - val isIncoming = intent.getBooleanExtra(EXTRA_IS_INCOMING, false) - if (isIncoming) { - // incoming always have a transaction id - viewModel.initIncoming(session, intent.getStringExtra(EXTRA_OTHER_USER_ID), transactionID) - } else { - viewModel.initOutgoing(session, intent.getStringExtra(EXTRA_OTHER_USER_ID), intent.getStringExtra(EXTRA_OTHER_DEVICE_ID)) - } - - if (isIncoming) { - val incoming = viewModel.transaction as? IncomingSasVerificationTransaction - when (incoming?.uxState) { - null, - IncomingSasVerificationTransaction.UxState.UNKNOWN, - IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT, - IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT -> { - supportActionBar?.setTitle(R.string.sas_incoming_request_title) - supportFragmentManager.commitTransaction { - setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out) - replace(R.id.container, SASVerificationIncomingFragment::class.java, null) - } - } - IncomingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION, - IncomingSasVerificationTransaction.UxState.SHOW_SAS -> { - supportFragmentManager.commitTransaction { - setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out) - replace(R.id.container, SASVerificationShortCodeFragment::class.java, null) - } - } - IncomingSasVerificationTransaction.UxState.VERIFIED -> { - supportFragmentManager.commitTransaction { - setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out) - replace(R.id.container, SASVerificationVerifiedFragment::class.java, null) - } - } - IncomingSasVerificationTransaction.UxState.CANCELLED_BY_ME, - IncomingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER -> { - viewModel.navigateCancel() - } - } - } else { - val outgoing = viewModel.transaction as? OutgoingSasVerificationRequest - // transaction can be null, as not yet created - when (outgoing?.uxState) { - null, - OutgoingSasVerificationRequest.UxState.UNKNOWN, - OutgoingSasVerificationRequest.UxState.WAIT_FOR_START, - OutgoingSasVerificationRequest.UxState.WAIT_FOR_KEY_AGREEMENT -> { - supportFragmentManager.commitTransaction { - setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out) - replace(R.id.container, SASVerificationStartFragment::class.java, null) - } - } - OutgoingSasVerificationRequest.UxState.SHOW_SAS, - OutgoingSasVerificationRequest.UxState.WAIT_FOR_VERIFICATION -> { - supportFragmentManager.commitTransaction { - setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out) - replace(R.id.container, SASVerificationShortCodeFragment::class.java, null) - } - } - OutgoingSasVerificationRequest.UxState.VERIFIED -> { - supportFragmentManager.commitTransaction { - setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out) - replace(R.id.container, SASVerificationVerifiedFragment::class.java, null) - } - } - OutgoingSasVerificationRequest.UxState.CANCELLED_BY_ME, - OutgoingSasVerificationRequest.UxState.CANCELLED_BY_OTHER -> { - viewModel.navigateCancel() - } - } - } - } - - viewModel.navigateEvent.observeEvent(this) { uxStateEvent -> - when (uxStateEvent) { - SasVerificationViewModel.NAVIGATE_FINISH -> { - finish() - } - SasVerificationViewModel.NAVIGATE_FINISH_SUCCESS -> { - val dataResult = Intent() - dataResult.putExtra(EXTRA_OTHER_DEVICE_ID, viewModel.otherDeviceId) - dataResult.putExtra(EXTRA_OTHER_USER_ID, viewModel.otherUserId) - setResult(Activity.RESULT_OK, dataResult) - finish() - } - SasVerificationViewModel.NAVIGATE_SAS_DISPLAY -> { - supportFragmentManager.commitTransaction { - setCustomAnimations(R.anim.enter_from_right, R.anim.exit_fade_out) - replace(R.id.container, SASVerificationShortCodeFragment::class.java, null) - } - } - SasVerificationViewModel.NAVIGATE_SUCCESS -> { - supportFragmentManager.commitTransaction { - setCustomAnimations(R.anim.enter_from_right, R.anim.exit_fade_out) - replace(R.id.container, SASVerificationVerifiedFragment::class.java, null) - } - } - SasVerificationViewModel.NAVIGATE_CANCELLED -> { - val isCancelledByMe = viewModel.transaction?.state == SasVerificationTxState.Cancelled - val humanReadableReason = when (viewModel.transaction?.cancelledReason) { - CancelCode.User -> getString(R.string.sas_error_m_user) - CancelCode.Timeout -> getString(R.string.sas_error_m_timeout) - CancelCode.UnknownTransaction -> getString(R.string.sas_error_m_unknown_transaction) - CancelCode.UnknownMethod -> getString(R.string.sas_error_m_unknown_method) - CancelCode.MismatchedCommitment -> getString(R.string.sas_error_m_mismatched_commitment) - CancelCode.MismatchedSas -> getString(R.string.sas_error_m_mismatched_sas) - CancelCode.UnexpectedMessage -> getString(R.string.sas_error_m_unexpected_message) - CancelCode.InvalidMessage -> getString(R.string.sas_error_m_invalid_message) - CancelCode.MismatchedKeys -> getString(R.string.sas_error_m_key_mismatch) - // Use user error - CancelCode.UserMismatchError -> getString(R.string.sas_error_m_user_error) - null -> getString(R.string.sas_error_unknown) - } - val message = - if (isCancelledByMe) getString(R.string.sas_cancelled_by_me, humanReadableReason) - else getString(R.string.sas_cancelled_by_other, humanReadableReason) - // Show a dialog - if (!this.isFinishing) { - AlertDialog.Builder(this) - .setTitle(R.string.sas_cancelled_dialog_title) - .setMessage(message) - .setCancelable(false) - .setPositiveButton(R.string.ok) { _, _ -> - // nop - finish() - } - .show() - } - } - } - } - - viewModel.loadingLiveEvent.observe(this, Observer { - if (it == null) { - hideWaitingView() - } else { - val status = if (it == -1) "" else getString(it) - updateWaitingView(WaitingViewData(status, isIndeterminate = true)) - } - }) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == android.R.id.home) { - // we want to cancel the transaction - viewModel.cancelTransaction() - } - - return super.onOptionsItemSelected(item) - } - - override fun onBackPressed() { - // we want to cancel the transaction - viewModel.cancelTransaction() - } -} diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationIncomingFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationIncomingFragment.kt deleted file mode 100644 index cb96900ba7..0000000000 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationIncomingFragment.kt +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2019 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.riotx.features.crypto.verification - -import android.os.Bundle -import android.widget.ImageView -import android.widget.TextView -import androidx.lifecycle.Observer -import butterknife.BindView -import butterknife.OnClick -import im.vector.matrix.android.api.session.crypto.sas.IncomingSasVerificationTransaction -import im.vector.matrix.android.api.util.MatrixItem -import im.vector.matrix.android.api.util.toMatrixItem -import im.vector.riotx.R -import im.vector.riotx.core.platform.VectorBaseFragment -import im.vector.riotx.features.home.AvatarRenderer -import javax.inject.Inject - -// TODO Deprecated("replaced by bottomsheet UX") -class SASVerificationIncomingFragment @Inject constructor( - private var avatarRenderer: AvatarRenderer -) : VectorBaseFragment() { - - @BindView(R.id.sas_incoming_request_user_display_name) - lateinit var otherUserDisplayNameTextView: TextView - - @BindView(R.id.sas_incoming_request_user_id) - lateinit var otherUserIdTextView: TextView - - @BindView(R.id.sas_incoming_request_user_device) - lateinit var otherDeviceTextView: TextView - - @BindView(R.id.sas_incoming_request_user_avatar) - lateinit var avatarImageView: ImageView - - override fun getLayoutResId() = R.layout.fragment_sas_verification_incoming_request - - private lateinit var viewModel: SasVerificationViewModel - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - - viewModel = activityViewModelProvider.get(SasVerificationViewModel::class.java) - - otherUserDisplayNameTextView.text = viewModel.otherUser?.displayName ?: viewModel.otherUserId - otherUserIdTextView.text = viewModel.otherUserId - otherDeviceTextView.text = viewModel.otherDeviceId - - viewModel.otherUser?.let { - avatarRenderer.render(it.toMatrixItem(), avatarImageView) - } ?: run { - // Fallback to what we know - avatarRenderer.render(MatrixItem.UserItem(viewModel.otherUserId ?: "", viewModel.otherUserId), avatarImageView) - } - - viewModel.transactionState.observe(viewLifecycleOwner, Observer { - val uxState = (viewModel.transaction as? IncomingSasVerificationTransaction)?.uxState - when (uxState) { - IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT -> { - viewModel.loadingLiveEvent.value = null - } - IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT -> { - viewModel.loadingLiveEvent.value = R.string.sas_waiting_for_partner - } - IncomingSasVerificationTransaction.UxState.SHOW_SAS -> { - viewModel.shortCodeReady() - } - IncomingSasVerificationTransaction.UxState.CANCELLED_BY_ME, - IncomingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER -> { - viewModel.loadingLiveEvent.value = null - viewModel.navigateCancel() - } - else -> Unit - } - }) - } - - @OnClick(R.id.sas_request_continue_button) - fun didAccept() { - viewModel.acceptTransaction() - } - - @OnClick(R.id.sas_request_cancel_button) - fun didCancel() { - viewModel.cancelTransaction() - } -} diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationShortCodeFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationShortCodeFragment.kt deleted file mode 100644 index 64c1c4b1f0..0000000000 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationShortCodeFragment.kt +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2019 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.riotx.features.crypto.verification - -import android.os.Bundle -import android.view.ViewGroup -import android.widget.TextView -import androidx.core.view.isInvisible -import androidx.core.view.isVisible -import androidx.lifecycle.Observer -import butterknife.BindView -import butterknife.OnClick -import im.vector.matrix.android.api.session.crypto.sas.IncomingSasVerificationTransaction -import im.vector.matrix.android.api.session.crypto.sas.OutgoingSasVerificationRequest -import im.vector.riotx.R -import im.vector.riotx.core.platform.VectorBaseFragment -import javax.inject.Inject - -// TODO Deprecated("replaced by bottomsheet UX") -class SASVerificationShortCodeFragment @Inject constructor(): VectorBaseFragment() { - - private lateinit var viewModel: SasVerificationViewModel - - @BindView(R.id.sas_decimal_code) - lateinit var decimalTextView: TextView - - @BindView(R.id.sas_emoji_description) - lateinit var descriptionTextView: TextView - - @BindView(R.id.sas_emoji_grid) - lateinit var emojiGrid: ViewGroup - - @BindView(R.id.emoji0) - lateinit var emoji0View: ViewGroup - @BindView(R.id.emoji1) - lateinit var emoji1View: ViewGroup - @BindView(R.id.emoji2) - lateinit var emoji2View: ViewGroup - @BindView(R.id.emoji3) - lateinit var emoji3View: ViewGroup - @BindView(R.id.emoji4) - lateinit var emoji4View: ViewGroup - @BindView(R.id.emoji5) - lateinit var emoji5View: ViewGroup - @BindView(R.id.emoji6) - lateinit var emoji6View: ViewGroup - - override fun getLayoutResId() = R.layout.fragment_sas_verification_display_code - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - viewModel = activityViewModelProvider.get(SasVerificationViewModel::class.java) - - viewModel.transaction?.let { - if (it.supportsEmoji()) { - val emojicodes = it.getEmojiCodeRepresentation() - emojicodes.forEachIndexed { index, emojiRepresentation -> - when (index) { - 0 -> { - emoji0View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji - emoji0View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId) - } - 1 -> { - emoji1View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji - emoji1View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId) - } - 2 -> { - emoji2View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji - emoji2View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId) - } - 3 -> { - emoji3View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji - emoji3View.findViewById(R.id.item_emoji_name_tv)?.setText(emojiRepresentation.nameResId) - } - 4 -> { - emoji4View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji - emoji4View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId) - } - 5 -> { - emoji5View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji - emoji5View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId) - } - 6 -> { - emoji6View.findViewById(R.id.item_emoji_tv).text = emojiRepresentation.emoji - emoji6View.findViewById(R.id.item_emoji_name_tv).setText(emojiRepresentation.nameResId) - } - } - } - } - - // decimal is at least supported - decimalTextView.text = it.getDecimalCodeRepresentation() - - if (it.supportsEmoji()) { - descriptionTextView.text = getString(R.string.sas_emoji_description) - decimalTextView.isVisible = false - emojiGrid.isVisible = true - } else { - descriptionTextView.text = getString(R.string.sas_decimal_description) - decimalTextView.isVisible = true - emojiGrid.isInvisible = true - } - } - - viewModel.transactionState.observe(viewLifecycleOwner, Observer { - if (viewModel.transaction is IncomingSasVerificationTransaction) { - val uxState = (viewModel.transaction as IncomingSasVerificationTransaction).uxState - when (uxState) { - IncomingSasVerificationTransaction.UxState.SHOW_SAS -> { - viewModel.loadingLiveEvent.value = null - } - IncomingSasVerificationTransaction.UxState.VERIFIED -> { - viewModel.loadingLiveEvent.value = null - viewModel.deviceIsVerified() - } - IncomingSasVerificationTransaction.UxState.CANCELLED_BY_ME, - IncomingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER -> { - viewModel.loadingLiveEvent.value = null - viewModel.navigateCancel() - } - else -> { - viewModel.loadingLiveEvent.value = R.string.sas_waiting_for_partner - } - } - } else if (viewModel.transaction is OutgoingSasVerificationRequest) { - val uxState = (viewModel.transaction as OutgoingSasVerificationRequest).uxState - when (uxState) { - OutgoingSasVerificationRequest.UxState.SHOW_SAS -> { - viewModel.loadingLiveEvent.value = null - } - OutgoingSasVerificationRequest.UxState.VERIFIED -> { - viewModel.loadingLiveEvent.value = null - viewModel.deviceIsVerified() - } - OutgoingSasVerificationRequest.UxState.CANCELLED_BY_ME, - OutgoingSasVerificationRequest.UxState.CANCELLED_BY_OTHER -> { - viewModel.loadingLiveEvent.value = null - viewModel.navigateCancel() - } - else -> { - viewModel.loadingLiveEvent.value = R.string.sas_waiting_for_partner - } - } - } - }) - } - - @OnClick(R.id.sas_request_continue_button) - fun didAccept() { - viewModel.confirmEmojiSame() - } - - @OnClick(R.id.sas_request_cancel_button) - fun didCancel() { - viewModel.cancelTransaction() - } -} diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationStartFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationStartFragment.kt deleted file mode 100644 index 4e9699e853..0000000000 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationStartFragment.kt +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2019 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.riotx.features.crypto.verification - -import android.os.Bundle -import android.view.ViewGroup -import android.widget.Button -import android.widget.ProgressBar -import android.widget.TextView -import androidx.core.view.isInvisible -import androidx.core.view.isVisible -import androidx.lifecycle.Observer -import androidx.transition.TransitionManager -import butterknife.BindView -import butterknife.OnClick -import im.vector.matrix.android.api.session.crypto.sas.OutgoingSasVerificationRequest -import im.vector.riotx.R -import im.vector.riotx.core.platform.VectorBaseActivity -import im.vector.riotx.core.platform.VectorBaseFragment -import javax.inject.Inject - -// TODO Deprecated("replaced by bottomsheet UX") -class SASVerificationStartFragment @Inject constructor(): VectorBaseFragment() { - - override fun getLayoutResId() = R.layout.fragment_sas_verification_start - - private lateinit var viewModel: SasVerificationViewModel - - @BindView(R.id.rootLayout) - lateinit var rootLayout: ViewGroup - - @BindView(R.id.sas_start_button) - lateinit var startButton: Button - - @BindView(R.id.sas_start_button_loading) - lateinit var startButtonLoading: ProgressBar - - @BindView(R.id.sas_verifying_keys) - lateinit var loadingText: TextView - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - viewModel = activityViewModelProvider.get(SasVerificationViewModel::class.java) - viewModel.transactionState.observe(viewLifecycleOwner, Observer { - val uxState = (viewModel.transaction as? OutgoingSasVerificationRequest)?.uxState - when (uxState) { - OutgoingSasVerificationRequest.UxState.WAIT_FOR_KEY_AGREEMENT -> { - // display loading - TransitionManager.beginDelayedTransition(this.rootLayout) - this.loadingText.isVisible = true - this.startButton.isInvisible = true - this.startButtonLoading.isVisible = true - this.startButtonLoading.animate() - } - OutgoingSasVerificationRequest.UxState.SHOW_SAS -> { - viewModel.shortCodeReady() - } - OutgoingSasVerificationRequest.UxState.CANCELLED_BY_ME, - OutgoingSasVerificationRequest.UxState.CANCELLED_BY_OTHER -> { - viewModel.navigateCancel() - } - else -> { - TransitionManager.beginDelayedTransition(this.rootLayout) - this.loadingText.isVisible = false - this.startButton.isVisible = true - this.startButtonLoading.isVisible = false - } - } - }) - } - - @OnClick(R.id.sas_start_button) - fun doStart() { - viewModel.beginSasKeyVerification() - } - - @OnClick(R.id.sas_legacy_verification) - fun doLegacy() { - (requireActivity() as VectorBaseActivity).notImplemented() - - /* - viewModel.session.crypto?.getDeviceInfo(viewModel.otherUserMxItem ?: "", viewModel.otherDeviceId - ?: "", object : SimpleApiCallback() { - override fun onSuccess(info: MXDeviceInfo?) { - info?.let { - - CommonActivityUtils.displayDeviceVerificationDialogLegacy(it, it.userId, viewModel.session, activity, object : YesNoListener { - override fun yes() { - viewModel.manuallyVerified() - } - - override fun no() { - - } - }) - } - } - }) - */ - } - - @OnClick(R.id.sas_cancel_button) - fun doCancel() { - // Transaction may be started, or not - viewModel.cancelTransaction() - } -} diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationVerifiedFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationVerifiedFragment.kt deleted file mode 100644 index fe7f9861b0..0000000000 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationVerifiedFragment.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2019 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.riotx.features.crypto.verification - -import android.os.Bundle -import butterknife.OnClick -import im.vector.riotx.R -import im.vector.riotx.core.platform.VectorBaseFragment -import javax.inject.Inject - -// TODO Deprecated("replaced by bottomsheet UX") -class SASVerificationVerifiedFragment @Inject constructor() : VectorBaseFragment() { - - override fun getLayoutResId() = R.layout.fragment_sas_verification_verified - - private lateinit var viewModel: SasVerificationViewModel - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - - viewModel = activityViewModelProvider.get(SasVerificationViewModel::class.java) - } - - @OnClick(R.id.sas_verification_verified_done_button) - fun onDone() { - viewModel.finishSuccess() - } -} diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SasVerificationViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SasVerificationViewModel.kt deleted file mode 100644 index ca283e449d..0000000000 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SasVerificationViewModel.kt +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2019 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.riotx.features.crypto.verification - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import im.vector.matrix.android.api.session.Session -import im.vector.matrix.android.api.session.crypto.sas.IncomingSasVerificationTransaction -import im.vector.matrix.android.api.session.crypto.sas.SasVerificationService -import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTransaction -import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState -import im.vector.matrix.android.api.session.user.model.User -import im.vector.riotx.core.utils.LiveEvent -import javax.inject.Inject - -// TODO Deprecated("replaced by bottomsheet UX") -class SasVerificationViewModel @Inject constructor() : ViewModel(), - SasVerificationService.SasVerificationListener { - - companion object { - const val NAVIGATE_FINISH = "NAVIGATE_FINISH" - const val NAVIGATE_FINISH_SUCCESS = "NAVIGATE_FINISH_SUCCESS" - const val NAVIGATE_SAS_DISPLAY = "NAVIGATE_SAS_DISPLAY" - const val NAVIGATE_SUCCESS = "NAVIGATE_SUCCESS" - const val NAVIGATE_CANCELLED = "NAVIGATE_CANCELLED" - } - - private lateinit var sasVerificationService: SasVerificationService - - var otherUserId: String? = null - var otherDeviceId: String? = null - var otherUser: User? = null - var transaction: SasVerificationTransaction? = null - - var transactionState: MutableLiveData = MutableLiveData() - - init { - // Force a first observe - transactionState.value = null - } - - private var _navigateEvent: MutableLiveData> = MutableLiveData() - val navigateEvent: LiveData> - get() = _navigateEvent - - var loadingLiveEvent: MutableLiveData = MutableLiveData() - - var transactionID: String? = null - set(value) { - if (value != null) { - transaction = sasVerificationService.getExistingTransaction(otherUserId!!, value) - transactionState.value = transaction?.state - otherDeviceId = transaction?.otherDeviceId - } - field = value - } - - fun initIncoming(session: Session, otherUserId: String, transactionID: String?) { - this.sasVerificationService = session.getSasVerificationService() - this.otherUserId = otherUserId - this.transactionID = transactionID - this.sasVerificationService.addListener(this) - this.otherUser = session.getUser(otherUserId) - if (transactionID == null || transaction == null) { - // sanity, this transaction is not known anymore - _navigateEvent.value = LiveEvent(NAVIGATE_FINISH) - } - } - - fun initOutgoing(session: Session, otherUserId: String, otherDeviceId: String) { - this.sasVerificationService = session.getSasVerificationService() - this.otherUserId = otherUserId - this.otherDeviceId = otherDeviceId - this.sasVerificationService.addListener(this) - this.otherUser = session.getUser(otherUserId) - } - - fun beginSasKeyVerification() { - val verificationSAS = sasVerificationService.beginKeyVerificationSAS(otherUserId!!, otherDeviceId!!) - this.transactionID = verificationSAS - } - - override fun transactionCreated(tx: SasVerificationTransaction) { - } - - override fun transactionUpdated(tx: SasVerificationTransaction) { - if (transactionID == tx.transactionId) { - transactionState.value = tx.state - } - } - - override fun markedAsManuallyVerified(userId: String, deviceId: String) { - } - - fun cancelTransaction() { - transaction?.cancel() - _navigateEvent.value = LiveEvent(NAVIGATE_FINISH) - } - - fun finishSuccess() { - _navigateEvent.value = LiveEvent(NAVIGATE_FINISH_SUCCESS) - } - - fun manuallyVerified() { - if (otherUserId != null && otherDeviceId != null) { - sasVerificationService.markedLocallyAsManuallyVerified(otherUserId!!, otherDeviceId!!) - } - _navigateEvent.value = LiveEvent(NAVIGATE_FINISH_SUCCESS) - } - - fun acceptTransaction() { - (transaction as? IncomingSasVerificationTransaction)?.performAccept() - } - - fun confirmEmojiSame() { - transaction?.userHasVerifiedShortCode() - } - - fun shortCodeReady() { - loadingLiveEvent.value = null - _navigateEvent.value = LiveEvent(NAVIGATE_SAS_DISPLAY) - } - - fun deviceIsVerified() { - loadingLiveEvent.value = null - _navigateEvent.value = LiveEvent(NAVIGATE_SUCCESS) - } - - fun navigateCancel() { - _navigateEvent.value = LiveEvent(NAVIGATE_CANCELLED) - } - - override fun onCleared() { - super.onCleared() - if (::sasVerificationService.isInitialized) { - sasVerificationService.removeListener(this) - } - } -} diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailAction.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailAction.kt index 358a5f3f57..d0716bd047 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailAction.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailAction.kt @@ -67,6 +67,6 @@ sealed class RoomDetailAction : VectorViewModelAction { data class AcceptVerificationRequest(val transactionId: String, val otherUserId: String, val otherdDeviceId: String) : RoomDetailAction() data class DeclineVerificationRequest(val transactionId: String, val otherUserId: String, val otherdDeviceId: String) : RoomDetailAction() - data class RequestVerification(val userId: String) : RoomDetailAction() + data class ResumeVerification(val transactionId: String, val otherUserId: String? = null, val otherdDeviceId: String? = null) : RoomDetailAction() } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt index 14e9061c36..fe4d0ae1f7 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt @@ -109,7 +109,7 @@ class RoomDetailActivity : VectorBaseActivity(), ToolbarConfigurable { companion object { - private const val EXTRA_ROOM_DETAIL_ARGS = "EXTRA_ROOM_DETAIL_ARGS" + const val EXTRA_ROOM_DETAIL_ARGS = "EXTRA_ROOM_DETAIL_ARGS" fun newIntent(context: Context, roomDetailArgs: RoomDetailArgs): Intent { return Intent(context, RoomDetailActivity::class.java).apply { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index 7e6d73eea7..7e84814da7 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -849,6 +849,15 @@ class RoomDetailFragment @Inject constructor( data.transactionId ).show(parentFragmentManager, "REQ") } + is RoomDetailAction.ResumeVerification -> { + val otherUserId = data.otherUserId ?: return + VerificationBottomSheet().apply { + arguments = Bundle().apply { + putParcelable(MvRx.KEY_ARG, VerificationBottomSheet.VerificationArgs( + otherUserId, data.transactionId, roomId = roomDetailArgs.roomId)) + } + }.show(parentFragmentManager, "REQ") + } } } } @@ -998,6 +1007,9 @@ class RoomDetailFragment @Inject constructor( } override fun onEventCellClicked(informationData: MessageInformationData, messageContent: MessageContent?, view: View) { + if (messageContent is MessageVerificationRequestContent) { + roomDetailViewModel.handle(RoomDetailAction.ResumeVerification(informationData.eventId)) + } } override fun onEventLongClicked(informationData: MessageInformationData, messageContent: MessageContent?, view: View): Boolean { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index 9fb08c2efe..c8a8e6413f 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -187,6 +187,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro is RoomDetailAction.AcceptVerificationRequest -> handleAcceptVerification(action) is RoomDetailAction.DeclineVerificationRequest -> handleDeclineVerification(action) is RoomDetailAction.RequestVerification -> handleRequestVerification(action) + is RoomDetailAction.ResumeVerification -> handleResumeRequestVerification(action) } } @@ -824,6 +825,18 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro _requestLiveData.postValue(LiveEvent(Success(action))) } + private fun handleResumeRequestVerification(action: RoomDetailAction.ResumeVerification) { + // Check if this request is still active and handled by me + session.getSasVerificationService().getExistingVerificationRequestInRoom(room.roomId, action.transactionId)?.let { + if (it.handledByOtherSession) return + if (!it.isFinished) { + _requestLiveData.postValue(LiveEvent(Success(action.copy( + otherUserId = it.otherUserId + )))) + } + } + } + private fun observeSyncState() { session.rx() .liveSyncState() diff --git a/vector/src/main/java/im/vector/riotx/features/popup/PopupAlertManager.kt b/vector/src/main/java/im/vector/riotx/features/popup/PopupAlertManager.kt index 664ea79fd2..6d92d36d38 100644 --- a/vector/src/main/java/im/vector/riotx/features/popup/PopupAlertManager.kt +++ b/vector/src/main/java/im/vector/riotx/features/popup/PopupAlertManager.kt @@ -20,12 +20,12 @@ import android.os.Build import android.os.Handler import android.os.Looper import android.view.View +import androidx.annotation.ColorInt import androidx.annotation.ColorRes import androidx.annotation.DrawableRes import com.tapadoo.alerter.Alerter import com.tapadoo.alerter.OnHideAlertListener import im.vector.riotx.R -import im.vector.riotx.features.crypto.verification.SASVerificationActivity import timber.log.Timber import java.lang.ref.WeakReference @@ -78,8 +78,7 @@ object PopupAlertManager { setLightStatusBar() } } - - if (shouldIgnoreActivity(activity)) { + if (currentAlerter?.shouldBeDisplayedIn?.invoke(activity) == false) { return } @@ -108,8 +107,6 @@ object PopupAlertManager { } } - private fun shouldIgnoreActivity(activity: Activity) = activity is SASVerificationActivity - private fun displayNextIfPossible() { val currentActivity = weakCurrentActivity?.get() if (Alerter.isShowing || currentActivity == null) { @@ -209,7 +206,13 @@ object PopupAlertManager { }) .enableSwipeToDismiss() .enableInfiniteDuration(true) - .setBackgroundColorRes(alert.colorRes ?: R.color.notification_accent_color) + .apply { + if (alert.colorInt != null) { + setBackgroundColorInt(alert.colorInt!!) + } else { + setBackgroundColorRes(alert.colorRes ?: R.color.notification_accent_color) + } + } .show() } @@ -229,7 +232,8 @@ object PopupAlertManager { data class VectorAlert(val uid: String, val title: String, val description: String, - @DrawableRes val iconId: Int?) { + @DrawableRes val iconId: Int?, + val shouldBeDisplayedIn: ((Activity) -> Boolean)? = null) { data class Button(val title: String, val action: Runnable, val autoClose: Boolean) @@ -250,5 +254,8 @@ object PopupAlertManager { @ColorRes var colorRes: Int? = null + + @ColorInt + var colorInt: Int? = null } } diff --git a/vector/src/main/res/layout/fragment_sas_verification_display_code.xml b/vector/src/main/res/layout/fragment_sas_verification_display_code.xml deleted file mode 100644 index 2d3a3135cb..0000000000 --- a/vector/src/main/res/layout/fragment_sas_verification_display_code.xml +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_sas_verification_incoming_request.xml b/vector/src/main/res/layout/fragment_sas_verification_incoming_request.xml deleted file mode 100644 index 67815d3e65..0000000000 --- a/vector/src/main/res/layout/fragment_sas_verification_incoming_request.xml +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_sas_verification_start.xml b/vector/src/main/res/layout/fragment_sas_verification_start.xml deleted file mode 100644 index edc7e8f7e3..0000000000 --- a/vector/src/main/res/layout/fragment_sas_verification_start.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_sas_verification_verified.xml b/vector/src/main/res/layout/fragment_sas_verification_verified.xml deleted file mode 100644 index 170f977620..0000000000 --- a/vector/src/main/res/layout/fragment_sas_verification_verified.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file