Start plugin QR code to the code

This commit is contained in:
Benoit Marty 2020-01-22 15:56:43 +01:00
parent 537b1be0c5
commit 79df6b8402
11 changed files with 138 additions and 24 deletions

View file

@ -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)
}

View file

@ -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

View file

@ -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)
}

View file

@ -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

View file

@ -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()
}

View file

@ -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<VerificationBottomSheetViewState, VerificationAction>(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)

View file

@ -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 {

View file

@ -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<out String>, 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
))
}
}

View file

@ -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
)
}

View file

@ -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<BottomShee
@EpoxyAttribute
var imageRes: Int = 0
@EpoxyAttribute
var imageBitmap: Bitmap? = null
@EpoxyAttribute
var contentDescription: String? = null
override fun bind(holder: Holder) {
holder.image.setImageResource(imageRes)
imageBitmap?.let {
holder.image.setImageBitmap(it)
} ?: run {
holder.image.setImageResource(imageRes)
}
if (contentDescription == null) {
ViewCompat.setImportantForAccessibility(holder.image, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO)

View file

@ -19,6 +19,7 @@ package im.vector.riotx.features.qrcode
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import com.google.zxing.BarcodeFormat
import com.google.zxing.Result
import im.vector.riotx.R
@ -57,10 +58,15 @@ class QrCodeScannerActivity : VectorBaseActivity() {
const val QR_CODE_SCANNER_REQUEST_CODE = 429
// For test only
fun startForResult(activity: Activity, requestCode: Int = QR_CODE_SCANNER_REQUEST_CODE) {
activity.startActivityForResult(Intent(activity, QrCodeScannerActivity::class.java), requestCode)
}
fun startForResult(fragment: Fragment, requestCode: Int = QR_CODE_SCANNER_REQUEST_CODE) {
fragment.startActivityForResult(Intent(fragment.requireActivity(), QrCodeScannerActivity::class.java), requestCode)
}
fun getResultText(data: Intent?): String? {
return data?.getStringExtra(EXTRA_OUT_TEXT)
}