From 79df6b840272a12e20e710cf20001b8c373e0c11 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 22 Jan 2020 15:56:43 +0100 Subject: [PATCH] Start plugin QR code to the code --- .../crypto/sas/SasVerificationTransaction.kt | 5 +- .../SASVerificationTransaction.kt | 6 ++- .../riotx/features/debug/DebugMenuActivity.kt | 4 +- .../im/vector/riotx/core/qrcode/QrCode.kt | 7 ++- .../crypto/verification/VerificationAction.kt | 28 ++++++++++ .../VerificationBottomSheetViewModel.kt | 28 ++++++---- .../VerificationChooseMethodController.kt | 12 +++-- .../VerificationChooseMethodFragment.kt | 51 ++++++++++++++++++- .../VerificationChooseMethodViewModel.kt | 5 ++ .../BottomSheetVerificationBigImageItem.kt | 10 +++- .../features/qrcode/QrCodeScannerActivity.kt | 6 +++ 11 files changed, 138 insertions(+), 24 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationAction.kt diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationTransaction.kt index e4e0baa3ac..640bc501e9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/crypto/sas/SasVerificationTransaction.kt @@ -50,5 +50,8 @@ interface SasVerificationTransaction { fun shortCodeDoesNotMatch() - fun isToDeviceTransport() : Boolean + fun isToDeviceTransport(): Boolean + + // TODO Not sure this is the right place to add this, because it is not Sas + fun userHasScannedRemoteQrCode(scannedData: String) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASVerificationTransaction.kt index c0dfc73129..7742d328ad 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASVerificationTransaction.kt @@ -204,7 +204,7 @@ internal abstract class SASVerificationTransaction( cancel(CancelCode.MismatchedSas) } - override fun isToDeviceTransport() : Boolean { + override fun isToDeviceTransport(): Boolean { return transport is SasTransportToDevice } @@ -228,6 +228,10 @@ internal abstract class SASVerificationTransaction( abstract fun onKeyVerificationMac(vKey: VerificationInfoMac) + override fun userHasScannedRemoteQrCode(scannedData: String) { + // TODO + } + protected fun verifyMacs() { Timber.v("## SAS verifying macs for id:$transactionId") state = SasVerificationTxState.Verifying diff --git a/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt b/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt index 8d013ceb2d..767f8cf7e1 100644 --- a/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt +++ b/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt @@ -38,7 +38,7 @@ import im.vector.riotx.R import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.core.di.ScreenComponent import im.vector.riotx.core.platform.VectorBaseActivity -import im.vector.riotx.core.qrcode.createQrCode +import im.vector.riotx.core.qrcode.toQrCode import im.vector.riotx.core.utils.PERMISSIONS_FOR_TAKING_PHOTO import im.vector.riotx.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA import im.vector.riotx.core.utils.allGranted @@ -65,7 +65,7 @@ class DebugMenuActivity : VectorBaseActivity() { } private fun renderQrCode(text: String) { - val qrBitmap = createQrCode(text) + val qrBitmap = text.toQrCode() debug_qr_code.setImageBitmap(qrBitmap) } diff --git a/vector/src/main/java/im/vector/riotx/core/qrcode/QrCode.kt b/vector/src/main/java/im/vector/riotx/core/qrcode/QrCode.kt index 8610c5a8af..a4e7ee2e07 100644 --- a/vector/src/main/java/im/vector/riotx/core/qrcode/QrCode.kt +++ b/vector/src/main/java/im/vector/riotx/core/qrcode/QrCode.kt @@ -22,11 +22,10 @@ import com.google.zxing.BarcodeFormat import com.google.zxing.common.BitMatrix import com.google.zxing.qrcode.QRCodeWriter -fun createQrCode(url: String, - width: Int = 200, - height: Int = 200): Bitmap { +fun String.toQrCode(width: Int = 200, + height: Int = 200): Bitmap { return QRCodeWriter().encode( - url, + this, BarcodeFormat.QR_CODE, width, height diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationAction.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationAction.kt new file mode 100644 index 0000000000..de3ea98df5 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationAction.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2020 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 im.vector.riotx.core.platform.VectorViewModelAction + +sealed class VerificationAction : VectorViewModelAction { + data class RequestVerificationByDM(val userID: String, val roomId: String?) : VerificationAction() + data class StartSASVerification(val userID: String, val pendingRequestTransactionId: String) : VerificationAction() + data class RemoteQrCodeScanned(val userID: String, val sasTransactionId: String, val scannedData: String) : VerificationAction() + data class SASMatchAction(val userID: String, val sasTransactionId: String) : VerificationAction() + data class SASDoNotMatchAction(val userID: String, val sasTransactionId: String) : VerificationAction() + object GotItConclusion : VerificationAction() +} diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt index 4008207b62..5f8c33f610 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/VerificationBottomSheetViewModel.kt @@ -17,17 +17,25 @@ package im.vector.riotx.features.crypto.verification import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData -import com.airbnb.mvrx.* +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.FragmentViewModelContext +import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.MvRxViewModelFactory +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.session.Session -import im.vector.matrix.android.api.session.crypto.sas.* +import im.vector.matrix.android.api.session.crypto.sas.CancelCode +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.crypto.sas.VerificationMethod import im.vector.matrix.android.api.util.MatrixItem import im.vector.matrix.android.api.util.toMatrixItem import im.vector.matrix.android.internal.crypto.verification.PendingVerificationRequest import im.vector.riotx.core.di.HasScreenInjector import im.vector.riotx.core.platform.VectorViewModel -import im.vector.riotx.core.platform.VectorViewModelAction import im.vector.riotx.core.utils.LiveEvent data class VerificationBottomSheetViewState( @@ -39,14 +47,6 @@ data class VerificationBottomSheetViewState( val cancelCode: CancelCode? = null ) : MvRxState -sealed class VerificationAction : VectorViewModelAction { - data class RequestVerificationByDM(val userID: String, val roomId: String?) : VerificationAction() - data class StartSASVerification(val userID: String, val pendingRequestTransactionId: String) : VerificationAction() - data class SASMatchAction(val userID: String, val sasTransactionId: String) : VerificationAction() - data class SASDoNotMatchAction(val userID: String, val sasTransactionId: String) : VerificationAction() - object GotItConclusion : VerificationAction() -} - class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted initialState: VerificationBottomSheetViewState, private val session: Session) : VectorViewModel(initialState), @@ -122,6 +122,12 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini callback = null ) } + is VerificationAction.RemoteQrCodeScanned -> { + // TODO Use session.getCrossSigningService()? + session.getSasVerificationService() + .getExistingTransaction(action.userID, action.sasTransactionId) + ?.userHasScannedRemoteQrCode(action.scannedData) + } is VerificationAction.SASMatchAction -> { session.getSasVerificationService() .getExistingTransaction(action.userID, action.sasTransactionId) diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodController.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodController.kt index 8760a8603e..5cec77f368 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodController.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodController.kt @@ -19,8 +19,10 @@ package im.vector.riotx.features.crypto.verification.choose import com.airbnb.epoxy.EpoxyController import im.vector.riotx.R import im.vector.riotx.core.epoxy.dividerItem +import im.vector.riotx.core.qrcode.toQrCode import im.vector.riotx.core.resources.ColorProvider import im.vector.riotx.core.resources.StringProvider +import im.vector.riotx.core.utils.DimensionConverter import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationActionItem import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationBigImageItem import im.vector.riotx.features.crypto.verification.epoxy.bottomSheetVerificationNoticeItem @@ -28,7 +30,8 @@ import javax.inject.Inject class VerificationChooseMethodController @Inject constructor( private val stringProvider: StringProvider, - private val colorProvider: ColorProvider + private val colorProvider: ColorProvider, + private val dimensionConverter: DimensionConverter ) : EpoxyController() { var listener: Listener? = null @@ -49,10 +52,13 @@ class VerificationChooseMethodController @Inject constructor( notice(stringProvider.getString(R.string.verification_scan_notice)) } - // TODO Generate the QR code + // Generate the QR code + val size = dimensionConverter.dpToPx(180) + val qrCodeBitmap = state.QRtext?.toQrCode(size, size) + bottomSheetVerificationBigImageItem { id("qr") - imageRes(R.drawable.riotx_logo) + imageBitmap(qrCodeBitmap) } dividerItem { diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodFragment.kt index b782afca39..110047b49c 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodFragment.kt @@ -15,6 +15,8 @@ */ package im.vector.riotx.features.crypto.verification.choose +import android.app.Activity +import android.content.Intent import android.os.Bundle import android.view.View import com.airbnb.mvrx.fragmentViewModel @@ -24,9 +26,15 @@ import im.vector.riotx.R import im.vector.riotx.core.extensions.cleanup import im.vector.riotx.core.extensions.configureWith import im.vector.riotx.core.platform.VectorBaseFragment +import im.vector.riotx.core.utils.PERMISSIONS_FOR_TAKING_PHOTO +import im.vector.riotx.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA +import im.vector.riotx.core.utils.allGranted +import im.vector.riotx.core.utils.checkPermissions import im.vector.riotx.features.crypto.verification.VerificationAction import im.vector.riotx.features.crypto.verification.VerificationBottomSheetViewModel +import im.vector.riotx.features.qrcode.QrCodeScannerActivity import kotlinx.android.synthetic.main.bottom_sheet_verification_child_fragment.* +import timber.log.Timber import javax.inject.Inject class VerificationChooseMethodFragment @Inject constructor( @@ -68,6 +76,47 @@ class VerificationChooseMethodFragment @Inject constructor( } override fun openCamera() { - // TODO + if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) { + doOpenQRCodeScanner() + } + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + + if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA && allGranted(grantResults)) { + doOpenQRCodeScanner() + } + } + + private fun doOpenQRCodeScanner() { + QrCodeScannerActivity.startForResult(this) + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + QrCodeScannerActivity.QR_CODE_SCANNER_REQUEST_CODE -> { + val scannedQrCode = QrCodeScannerActivity.getResultText(data) + val wasQrCode = QrCodeScannerActivity.getResultIsQrCode(data) + + if (wasQrCode && !scannedQrCode.isNullOrBlank()) { + onRemoteQrCodeScanned(scannedQrCode) + } else { + Timber.w("It was not a QR code, or empty result") + } + } + } + } + } + + private fun onRemoteQrCodeScanned(remoteQrCode: String) = withState(sharedViewModel) { + sharedViewModel.handle(VerificationAction.RemoteQrCodeScanned( + it.otherUserMxItem?.id ?: "", + it.pendingRequest?.transactionId ?: "", + remoteQrCode + )) } } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt index a1d566d77b..cd28a2b709 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/choose/VerificationChooseMethodViewModel.kt @@ -35,6 +35,7 @@ data class VerificationChooseMethodViewState( val otherUserId: String = "", val transactionId: String = "", val QRModeAvailable: Boolean = false, + val QRtext: String? = null, val SASModeAvailable: Boolean = false ) : MvRxState @@ -55,6 +56,8 @@ class VerificationChooseMethodViewModel @AssistedInject constructor( setState { copy( QRModeAvailable = qrAvailable, + // TODO + QRtext = "https://www.example.org", SASModeAvailable = emojiAvailable ) } @@ -90,6 +93,8 @@ class VerificationChooseMethodViewModel @AssistedInject constructor( return VerificationChooseMethodViewState(otherUserId = args.otherUserId, transactionId = args.verificationId ?: "", QRModeAvailable = qrAvailable, + // TODO + QRtext = "https://www.example.org", SASModeAvailable = emojiAvailable ) } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationBigImageItem.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationBigImageItem.kt index 5163f5e8a8..4973f425cd 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationBigImageItem.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/epoxy/BottomSheetVerificationBigImageItem.kt @@ -16,6 +16,7 @@ */ package im.vector.riotx.features.crypto.verification.epoxy +import android.graphics.Bitmap import android.widget.ImageView import androidx.core.view.ViewCompat import com.airbnb.epoxy.EpoxyAttribute @@ -33,11 +34,18 @@ abstract class BottomSheetVerificationBigImageItem : VectorEpoxyModel