Verify that the node is synced before trying to broadcast a transaction in TransactionsActivity, to avoid users confusion. Ideally, the app should not be connected to an out of sync node, but this is in case that still happens.

This commit is contained in:
Severiano Jaramillo 2019-04-25 17:43:07 -05:00
parent 01a2bc1a53
commit 8af2042039
2 changed files with 23 additions and 11 deletions

View file

@ -1,6 +1,5 @@
package cy.agorise.bitsybitshareswallet.fragments package cy.agorise.bitsybitshareswallet.fragments
import android.Manifest
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
@ -10,6 +9,7 @@ import android.view.*
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.collection.LongSparseArray
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
@ -99,7 +99,7 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
private var mSelectedUserAccount: UserAccount? = null private var mSelectedUserAccount: UserAccount? = null
// Map used to keep track of request and response id pairs // Map used to keep track of request and response id pairs
private val responseMap = HashMap<Long, Int>() private val responseMap = LongSparseArray<Int>()
/** Transaction being built */ /** Transaction being built */
private var transaction: Transaction? = null private var transaction: Transaction? = null
@ -147,7 +147,7 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
mViewModel= ViewModelProviders.of(this).get(SendTransactionViewModel::class.java) mViewModel= ViewModelProviders.of(this).get(SendTransactionViewModel::class.java)
mViewModel.getWIF(userId, AuthorityType.ACTIVE.ordinal).observe(this, mViewModel.getWIF(userId, AuthorityType.ACTIVE.ordinal).observe(this,
androidx.lifecycle.Observer<String> { encryptedWIF -> Observer<String> { encryptedWIF ->
context?.let { context?.let {
try { try {
wifKey = CryptoUtils.decrypt(it, encryptedWIF) wifKey = CryptoUtils.decrypt(it, encryptedWIF)
@ -243,8 +243,7 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
override fun handleJsonRpcResponse(response: JsonRpcResponse<*>) { override fun handleJsonRpcResponse(response: JsonRpcResponse<*>) {
if (responseMap.containsKey(response.id)) { if (responseMap.containsKey(response.id)) {
val responseType = responseMap[response.id] when (responseMap[response.id]) {
when (responseType) {
RESPONSE_GET_ACCOUNT_BY_NAME -> handleAccountProperties(response.result) RESPONSE_GET_ACCOUNT_BY_NAME -> handleAccountProperties(response.result)
RESPONSE_GET_DYNAMIC_GLOBAL_PROPERTIES -> handleDynamicGlobalProperties(response.result) RESPONSE_GET_DYNAMIC_GLOBAL_PROPERTIES -> handleDynamicGlobalProperties(response.result)
RESPONSE_GET_REQUIRED_FEES -> handleRequiredFees(response.result) RESPONSE_GET_REQUIRED_FEES -> handleRequiredFees(response.result)
@ -285,7 +284,17 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
* calls the next step which is [GetRequiredFees] else it shows an error */ * calls the next step which is [GetRequiredFees] else it shows an error */
private fun handleDynamicGlobalProperties(result: Any?) { private fun handleDynamicGlobalProperties(result: Any?) {
if (result is DynamicGlobalProperties) { if (result is DynamicGlobalProperties) {
val expirationTime = (result.time.time / 1000) + Transaction.DEFAULT_EXPIRATION_TIME
val now = System.currentTimeMillis() / 1000
val time = result.time.time / 1000
// Show an error if the current connected node is out of sync
if (now - time > Constants.CHECK_NODE_OUT_OF_SYNC) {
context?.toast(getString(R.string.msg__transaction_not_sent))
return
}
val expirationTime = time + Transaction.DEFAULT_EXPIRATION_TIME
val headBlockId = result.head_block_id val headBlockId = result.head_block_id
val headBlockNumber = result.head_block_number val headBlockNumber = result.head_block_number
@ -294,7 +303,7 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
val asset = Asset(mBalancesDetailsAdapter!!.getItem(spAsset.selectedItemPosition)!!.id) val asset = Asset(mBalancesDetailsAdapter!!.getItem(spAsset.selectedItemPosition)!!.id)
val id = mNetworkService?.sendMessage(GetRequiredFees(transaction!!, asset), GetRequiredFees.REQUIRED_API) val id = mNetworkService?.sendMessage(GetRequiredFees(transaction!!, asset), GetRequiredFees.REQUIRED_API)
if (id != null) responseMap[id] = RESPONSE_GET_REQUIRED_FEES if (id != null) responseMap.append(id, RESPONSE_GET_REQUIRED_FEES)
} else { } else {
context?.toast(getString(R.string.msg__transaction_not_sent)) context?.toast(getString(R.string.msg__transaction_not_sent))
} }
@ -308,7 +317,7 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
transaction!!.setFees(result as List<AssetAmount>) // TODO find how to remove this warning transaction!!.setFees(result as List<AssetAmount>) // TODO find how to remove this warning
val id = mNetworkService?.sendMessage(BroadcastTransaction(transaction), BroadcastTransaction.REQUIRED_API) val id = mNetworkService?.sendMessage(BroadcastTransaction(transaction), BroadcastTransaction.REQUIRED_API)
if (id != null) responseMap[id] = RESPONSE_BROADCAST_TRANSACTION if (id != null) responseMap.append(id, RESPONSE_BROADCAST_TRANSACTION)
} else { } else {
context?.toast(getString(R.string.msg__transaction_not_sent)) context?.toast(getString(R.string.msg__transaction_not_sent))
} }
@ -329,7 +338,7 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
/** Verifies if the user has already granted the Camera permission, if not the asks for it */ /** Verifies if the user has already granted the Camera permission, if not the asks for it */
private fun verifyCameraPermission() { private fun verifyCameraPermission() {
if (ContextCompat.checkSelfPermission(activity!!, Manifest.permission.CAMERA) if (ContextCompat.checkSelfPermission(activity!!, android.Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) { != PackageManager.PERMISSION_GRANTED) {
// Permission is not already granted // Permission is not already granted
requestPermissions(arrayOf(android.Manifest.permission.CAMERA), REQUEST_CAMERA_PERMISSION) requestPermissions(arrayOf(android.Manifest.permission.CAMERA), REQUEST_CAMERA_PERMISSION)
@ -442,7 +451,7 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
private fun validateAccount(accountName: String) { private fun validateAccount(accountName: String) {
isToAccountCorrect = false isToAccountCorrect = false
val id = mNetworkService?.sendMessage(GetAccountByName(accountName), GetAccountByName.REQUIRED_API) val id = mNetworkService?.sendMessage(GetAccountByName(accountName), GetAccountByName.REQUIRED_API)
if (id != null) responseMap[id] = RESPONSE_GET_ACCOUNT_BY_NAME if (id != null) responseMap.append(id, RESPONSE_GET_ACCOUNT_BY_NAME)
} }
private fun validateAmount() { private fun validateAmount() {
@ -570,7 +579,7 @@ class SendTransactionFragment : ConnectedFragment(), ZXingScannerView.ResultHand
// Start the send transaction procedure which includes a series of calls // Start the send transaction procedure which includes a series of calls
val id = mNetworkService?.sendMessage(GetDynamicGlobalProperties(), val id = mNetworkService?.sendMessage(GetDynamicGlobalProperties(),
GetDynamicGlobalProperties.REQUIRED_API) GetDynamicGlobalProperties.REQUIRED_API)
if (id != null ) responseMap[id] = RESPONSE_GET_DYNAMIC_GLOBAL_PROPERTIES if (id != null ) responseMap.append(id, RESPONSE_GET_DYNAMIC_GLOBAL_PROPERTIES)
} else } else
Log.d(TAG, "Network Service is not connected") Log.d(TAG, "Network Service is not connected")
} }

View file

@ -122,6 +122,9 @@ object Constants {
/** Name of the external storage folder used to save files like PDF and CSV exports and Backups **/ /** Name of the external storage folder used to save files like PDF and CSV exports and Backups **/
const val EXTERNAL_STORAGE_FOLDER = "BiTSy" const val EXTERNAL_STORAGE_FOLDER = "BiTSy"
/** Constant used to check if the current connected node is out of sync */
const val CHECK_NODE_OUT_OF_SYNC = 10 // 10 seconds
/////////////////////// Crashlytics custom keys /////////////////////// /////////////////////// Crashlytics custom keys ///////////////////////