From 962afe78c65137f5a540f966a627112032390774 Mon Sep 17 00:00:00 2001 From: Severiano Jaramillo Date: Sun, 23 Dec 2018 14:11:26 -0600 Subject: [PATCH] Create method to always observe the database for Missing transaction times, which automatically launches a call to the NetworkService to obtain such value from the corresponding transfer's blockNumber. This value is updated in the Database and shown in the corresponding transaction item in the Transactions screen automatically. --- .../activities/ConnectedActivity.kt | 68 ++++++++++++++++++- .../database/daos/TransferDao.kt | 10 ++- .../processors/TransfersLoader.kt | 3 - .../repositories/TransferRepository.kt | 17 +++++ .../viewmodels/TransferViewModel.kt | 18 +++++ 5 files changed, 108 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/cy/agorise/bitsybitshareswallet/viewmodels/TransferViewModel.kt diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/activities/ConnectedActivity.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/activities/ConnectedActivity.kt index 54ff0e2..5eb1c4d 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/activities/ConnectedActivity.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/activities/ConnectedActivity.kt @@ -18,6 +18,7 @@ import cy.agorise.bitsybitshareswallet.processors.TransfersLoader import cy.agorise.bitsybitshareswallet.repositories.AssetRepository import cy.agorise.bitsybitshareswallet.utils.Constants import cy.agorise.bitsybitshareswallet.viewmodels.BalanceViewModel +import cy.agorise.bitsybitshareswallet.viewmodels.TransferViewModel import cy.agorise.bitsybitshareswallet.viewmodels.UserAccountViewModel import cy.agorise.graphenej.Asset import cy.agorise.graphenej.AssetAmount @@ -27,12 +28,16 @@ import cy.agorise.graphenej.api.android.NetworkService import cy.agorise.graphenej.api.android.RxBus import cy.agorise.graphenej.api.calls.* import cy.agorise.graphenej.models.AccountProperties +import cy.agorise.graphenej.models.BlockHeader import cy.agorise.graphenej.models.FullAccountDetails import cy.agorise.graphenej.models.JsonRpcResponse import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable -import java.util.HashMap +import java.text.ParseException +import java.text.SimpleDateFormat +import java.util.* import kotlin.collections.ArrayList +import kotlin.collections.HashMap /** * Class in charge of managing the connection to graphenej's NetworkService @@ -44,9 +49,11 @@ abstract class ConnectedActivity : AppCompatActivity(), ServiceConnection { private val RESPONSE_GET_ACCOUNTS = 2 private val RESPONSE_GET_ACCOUNT_BALANCES = 3 private val RESPONSE_GET_ASSETS = 4 + private val RESPONSE_GET_BLOCK_HEADER = 5 private lateinit var mUserAccountViewModel: UserAccountViewModel private lateinit var mBalanceViewModel: BalanceViewModel + private lateinit var mTransferViewModel: TransferViewModel private lateinit var mAssetRepository: AssetRepository @@ -69,6 +76,11 @@ abstract class ConnectedActivity : AppCompatActivity(), ServiceConnection { // Map used to keep track of request and response id pairs private val responseMap = HashMap() + /** Map used to keep track of request id and block number pairs */ + private val requestIdToBlockNumberMap = HashMap() + + private var blockNumberWithMissingTime = 0L + /** * Flag used to keep track of the NetworkService binding state */ @@ -110,6 +122,17 @@ abstract class ConnectedActivity : AppCompatActivity(), ServiceConnection { } }) + //Configure TransferViewModel to obtain the Transfer's block numbers with missing time information, one by one + mTransferViewModel = ViewModelProviders.of(this).get(TransferViewModel::class.java) + + mTransferViewModel.getTransferBlockNumberWithMissingTime().observe(this, Observer{ blockNumber -> + if (blockNumber != null && blockNumber != blockNumberWithMissingTime) { + blockNumberWithMissingTime = blockNumber + Log.d(TAG, "Block number: $blockNumber, Time: ${System.currentTimeMillis()}") + mHandler.postDelayed(mRequestBlockMissingTimeTask, 10) + } + }) + mDisposable = RxBus.getBusInstance() .asFlowable() .observeOn(AndroidSchedulers.mainThread()) @@ -136,6 +159,12 @@ abstract class ConnectedActivity : AppCompatActivity(), ServiceConnection { RESPONSE_GET_ASSETS -> handleAssets(message.result as List) + + RESPONSE_GET_BLOCK_HEADER -> { + val blockNumber = requestIdToBlockNumberMap[message.id] ?: 0L + handleBlockHeader(message.result as BlockHeader, blockNumber) + requestIdToBlockNumberMap.remove(message.id) + } } responseMap.remove(message.id) } @@ -245,6 +274,22 @@ abstract class ConnectedActivity : AppCompatActivity(), ServiceConnection { missingAssets.clear() } + /** + * Receives the [BlockHeader] related to a Transfer's missing time and saves it into the database. + */ + private fun handleBlockHeader(blockHeader: BlockHeader, blockNumber: Long) { + + val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US) + dateFormat.timeZone = TimeZone.getTimeZone("GMT") + + try { + val date = dateFormat.parse(blockHeader.timestamp) + mTransferViewModel.setBlockTime(blockNumber, date.time / 1000) + } catch (e: ParseException) { + Log.e(TAG, "ParseException. Msg: " + e.message) + } + } + private fun updateBalances() { if (mNetworkService!!.isConnected) { val id = mNetworkService!!.sendMessage(GetAccountBalances(mCurrentAccount, ArrayList()), @@ -299,9 +344,26 @@ abstract class ConnectedActivity : AppCompatActivity(), ServiceConnection { responseMap[id] = RESPONSE_GET_FULL_ACCOUNTS } } else { - Log.w(TAG, "NetworkService is null or is not connected. mNetworkService: $mNetworkService") + mHandler.postDelayed(this, Constants.MISSING_PAYMENT_CHECK_PERIOD) + } + } + } + + /** + * Task used to obtain the missing time from a block from Graphenej's NetworkService. + */ + private val mRequestBlockMissingTimeTask = object : Runnable { + override fun run() { + + if (mNetworkService != null && mNetworkService!!.isConnected) { + val id = mNetworkService!!.sendMessage(GetBlockHeader(blockNumberWithMissingTime), + GetBlockHeader.REQUIRED_API) + + responseMap[id] = RESPONSE_GET_BLOCK_HEADER + requestIdToBlockNumberMap[id] = blockNumberWithMissingTime + } else { + mHandler.postDelayed(this, Constants.MISSING_PAYMENT_CHECK_PERIOD) } - mHandler.postDelayed(this, Constants.MISSING_PAYMENT_CHECK_PERIOD) } } diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/database/daos/TransferDao.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/database/daos/TransferDao.kt index f61a9e5..63aeaee 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/database/daos/TransferDao.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/database/daos/TransferDao.kt @@ -17,12 +17,18 @@ interface TransferDao { @Insert(onConflict = OnConflictStrategy.IGNORE) fun insertAll(transfers: List) - @Query("SELECT COUNT(*) FROM transfers") - fun getCount(): Single + @Query("UPDATE transfers SET timestamp=:timestamp WHERE block_number=:blockNumber") + fun setBlockTime(blockNumber: Long, timestamp: Long) @Query("SELECT * FROM transfers") fun getAll(): LiveData> + @Query("SELECT COUNT(*) FROM transfers") + fun getCount(): Single + + @Query("SELECT block_number FROM transfers WHERE timestamp='0' LIMIT 1") + fun getTransferBlockNumberWithMissingTime(): LiveData + @Query("DELETE FROM transfers") fun deleteAll() } \ No newline at end of file diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/processors/TransfersLoader.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/processors/TransfersLoader.kt index 13255b7..b099c54 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/processors/TransfersLoader.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/processors/TransfersLoader.kt @@ -7,9 +7,6 @@ import android.content.ServiceConnection import android.os.IBinder import android.preference.PreferenceManager import android.util.Log -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleObserver -import androidx.lifecycle.OnLifecycleEvent import cy.agorise.bitsybitshareswallet.database.entities.Transfer import cy.agorise.bitsybitshareswallet.models.HistoricalOperationEntry import cy.agorise.bitsybitshareswallet.repositories.AuthorityRepository diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/TransferRepository.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/TransferRepository.kt index 9c27bd2..7f328d5 100644 --- a/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/TransferRepository.kt +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/repositories/TransferRepository.kt @@ -21,6 +21,10 @@ class TransferRepository internal constructor(context: Context) { insertAllAsyncTask(mTransferDao).execute(transfers) } + fun setBlockTime(blockNumber: Long, timestamp: Long) { + setBlockTimeAsyncTask(mTransferDao).execute(Pair(blockNumber, timestamp)) + } + fun getAll(): LiveData> { return mTransferDao.getAll() } @@ -29,6 +33,10 @@ class TransferRepository internal constructor(context: Context) { return mTransferDao.getCount() } + fun getTransferBlockNumberWithMissingTime(): LiveData { + return mTransferDao.getTransferBlockNumberWithMissingTime() + } + fun deleteAll() { deleteAllAsyncTask(mTransferDao).execute() } @@ -42,6 +50,15 @@ class TransferRepository internal constructor(context: Context) { } } + private class setBlockTimeAsyncTask internal constructor(private val mAsyncTaskDao: TransferDao) : + AsyncTask, Void, Void>() { + + override fun doInBackground(vararg pair: Pair): Void? { + mAsyncTaskDao.setBlockTime(pair[0].first, pair[0].second) + return null + } + } + private class deleteAllAsyncTask internal constructor(private val mAsyncTaskDao: TransferDao) : AsyncTask() { diff --git a/app/src/main/java/cy/agorise/bitsybitshareswallet/viewmodels/TransferViewModel.kt b/app/src/main/java/cy/agorise/bitsybitshareswallet/viewmodels/TransferViewModel.kt new file mode 100644 index 0000000..484d72c --- /dev/null +++ b/app/src/main/java/cy/agorise/bitsybitshareswallet/viewmodels/TransferViewModel.kt @@ -0,0 +1,18 @@ +package cy.agorise.bitsybitshareswallet.viewmodels + +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.LiveData +import cy.agorise.bitsybitshareswallet.repositories.TransferRepository + +class TransferViewModel(application: Application) : AndroidViewModel(application) { + private var mRepository = TransferRepository(application) + + internal fun setBlockTime(blockNumber: Long, timestamp: Long) { + mRepository.setBlockTime(blockNumber, timestamp) + } + + internal fun getTransferBlockNumberWithMissingTime(): LiveData { + return mRepository.getTransferBlockNumberWithMissingTime() + } +} \ No newline at end of file