Fix crash in TransfersLoader when changing between night and day mode.

This commit is contained in:
Severiano Jaramillo 2019-01-31 14:59:40 -06:00
parent c7138c5e22
commit eaa661ba5d

View file

@ -24,10 +24,10 @@ import cy.agorise.graphenej.models.OperationHistory
import cy.agorise.graphenej.operations.TransferOperation import cy.agorise.graphenej.operations.TransferOperation
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.functions.Consumer
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import org.bitcoinj.core.DumpedPrivateKey import org.bitcoinj.core.DumpedPrivateKey
import org.bitcoinj.core.ECKey import org.bitcoinj.core.ECKey
import java.lang.IllegalArgumentException
import java.util.* import java.util.*
import javax.crypto.AEADBadTagException import javax.crypto.AEADBadTagException
@ -35,27 +35,22 @@ import javax.crypto.AEADBadTagException
* This class is responsible for loading the local database with all past transfer operations of the * This class is responsible for loading the local database with all past transfer operations of the
* currently selected account. * currently selected account.
* *
* The procedure used to load the database in 3 steps:
*
* 1- Load all transfer operations
* 2- Load all missing times
* 3- Load all missing equivalent times
*
* Since the 'get_relative_account_history' will not provide either timestamps nor equivalent values * Since the 'get_relative_account_history' will not provide either timestamps nor equivalent values
* for every transfer, we must first load all historical transfer operations, and then proceed to * for every transfer, that has to be handled in other part.
* handle those missing columns.
*/ */
class TransfersLoader(private var mContext: Context?): ServiceConnection { class TransfersLoader(private var mContext: Context?) {
private val TAG = this.javaClass.simpleName companion object {
private const val TAG = "TransfersLoader"
/** Constant that specifies if we are on debug mode */ /** Constant that specifies if we are on debug mode */
private val DEBUG = false private const val DEBUG = false
/* Constant used to fix the number of historical transfers to fetch from the network in one batch */ /* Constant used to fix the number of historical transfers to fetch from the network in one batch */
private val HISTORICAL_TRANSFER_BATCH_SIZE = 100 private const val HISTORICAL_TRANSFER_BATCH_SIZE = 100
private val RESPONSE_GET_RELATIVE_ACCOUNT_HISTORY = 0 private const val RESPONSE_GET_RELATIVE_ACCOUNT_HISTORY = 1
}
private var mDisposables = CompositeDisposable() private var mDisposables = CompositeDisposable()
@ -77,28 +72,26 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
/* Counter used to keep track of the transfer history batch count */ /* Counter used to keep track of the transfer history batch count */
private var historicalTransferCount = 0 private var historicalTransferCount = 0
// Used to keep track of the current state TODO this may not be needed /** Flag used to keep track of the NetworkService binding state */
private var mState = State.IDLE private var mBound: Boolean = false
/**
* Flag used to keep track of the NetworkService binding state
*/
private var mShouldUnbindNetwork: Boolean = false
private var lastId: Long = 0
// 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 = HashMap<Long, Int>()
/** private val mConnection = object : ServiceConnection {
* Enum class used to keep track of the current state of the loader override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
*/ // We've bound to LocalService, cast the IBinder and get LocalService instance
private enum class State { val binder = service as NetworkService.LocalBinder
IDLE, mNetworkService = binder.service
LOADING_MISSING_TIMES, mBound = true
LOADING_EQ_VALUES,
CANCELLED, // Start the transfers update
FINISHED startTransfersUpdateProcedure()
}
override fun onServiceDisconnected(name: ComponentName?) {
mBound = false
}
} }
init { init {
@ -106,10 +99,11 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
authorityRepository = AuthorityRepository(mContext!!) authorityRepository = AuthorityRepository(mContext!!)
val pref = PreferenceManager.getDefaultSharedPreferences(mContext) val pref = PreferenceManager.getDefaultSharedPreferences(mContext)
val userId = pref.getString(Constants.KEY_CURRENT_ACCOUNT_ID, "") val userId = pref.getString(Constants.KEY_CURRENT_ACCOUNT_ID, "") ?: ""
if (userId != "") { if (userId != "") {
mCurrentAccount = UserAccount(userId) mCurrentAccount = UserAccount(userId)
mDisposables.add(authorityRepository!!.getWIF(userId!!, AuthorityType.MEMO.ordinal) mDisposables.add(
authorityRepository!!.getWIF(userId, AuthorityType.MEMO.ordinal)
.subscribeOn(Schedulers.computation()) .subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { encryptedWIF -> .subscribe { encryptedWIF ->
@ -124,8 +118,7 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
mDisposables.add(RxBus.getBusInstance() mDisposables.add(RxBus.getBusInstance()
.asFlowable() .asFlowable()
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(Consumer { message -> .subscribe { message ->
if (mState == State.FINISHED) return@Consumer
if (message is JsonRpcResponse<*>) { if (message is JsonRpcResponse<*>) {
if (message.result is List<*>) { if (message.result is List<*>) {
if (responseMap.containsKey(message.id)) { if (responseMap.containsKey(message.id)) {
@ -143,37 +136,17 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
responseMap.clear() responseMap.clear()
} }
} }
})
)
} else {
// If there is no current user, we should not do anything
mState = State.CANCELLED
} }
)
onStart() onStart()
} }
override fun onServiceDisconnected(name: ComponentName?) {
mShouldUnbindNetwork = false
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
val binder = service as NetworkService.LocalBinder
mNetworkService = binder.service
// Start the transfers update
startTransfersUpdateProcedure()
} }
private fun onStart() { private fun onStart() {
if (mState != State.CANCELLED) { // Bind to LocalService
val intent = Intent(mContext, NetworkService::class.java) Intent(mContext, NetworkService::class.java).also { intent ->
if (mContext!!.bindService(intent, this, Context.BIND_AUTO_CREATE)) { mContext?.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
mShouldUnbindNetwork = true
} else {
Log.e(TAG, "Binding to the network service failed.")
}
} }
} }
@ -183,7 +156,7 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
private fun startTransfersUpdateProcedure() { private fun startTransfersUpdateProcedure() {
if (DEBUG) { if (DEBUG) {
// If we are in debug mode, we first erase all entries in the 'transfer' table // If we are in debug mode, we first erase all entries in the 'transfer' table
transferRepository!!.deleteAll() transferRepository?.deleteAll()
} }
mDisposables.add( mDisposables.add(
transferRepository!!.getCount() transferRepository!!.getCount()
@ -213,7 +186,7 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
private fun handleOperationList(operationHistoryList: List<OperationHistory>) { private fun handleOperationList(operationHistoryList: List<OperationHistory>) {
historicalTransferCount++ historicalTransferCount++
val insertedCount = transferRepository!!.insertAll(processOperationList(operationHistoryList)) val insertedCount = transferRepository?.insertAll(processOperationList(operationHistoryList))
// TODO return number of inserted rows // TODO return number of inserted rows
// Log.d(TAG, String.format("Inserted count: %d, list size: %d", insertedCount, operationHistoryList.size)) // Log.d(TAG, String.format("Inserted count: %d, list size: %d", insertedCount, operationHistoryList.size))
if (/* insertedCount == 0 && */ operationHistoryList.isEmpty()) { if (/* insertedCount == 0 && */ operationHistoryList.isEmpty()) {
@ -234,7 +207,7 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
private fun loadNextOperationsBatch() { private fun loadNextOperationsBatch() {
val stop = historicalTransferCount * HISTORICAL_TRANSFER_BATCH_SIZE val stop = historicalTransferCount * HISTORICAL_TRANSFER_BATCH_SIZE
val start = stop + HISTORICAL_TRANSFER_BATCH_SIZE val start = stop + HISTORICAL_TRANSFER_BATCH_SIZE
lastId = mNetworkService!!.sendMessage( val id = mNetworkService?.sendMessage(
GetRelativeAccountHistory( GetRelativeAccountHistory(
mCurrentAccount, mCurrentAccount,
stop, stop,
@ -242,7 +215,7 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
start start
), GetRelativeAccountHistory.REQUIRED_API ), GetRelativeAccountHistory.REQUIRED_API
) )
responseMap[lastId] = RESPONSE_GET_RELATIVE_ACCOUNT_HISTORY if (id != null) responseMap[id] = RESPONSE_GET_RELATIVE_ACCOUNT_HISTORY
} }
/** /**
@ -321,10 +294,15 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
private fun onDestroy() { private fun onDestroy() {
Log.d(TAG, "Destroying TransfersLoader") Log.d(TAG, "Destroying TransfersLoader")
if (!mDisposables.isDisposed) mDisposables.dispose() if (!mDisposables.isDisposed) mDisposables.dispose()
if (mShouldUnbindNetwork) {
mContext!!.unbindService(this) try {
mShouldUnbindNetwork = false if (mBound && mNetworkService != null)
mContext?.unbindService(mConnection)
} catch (e: IllegalArgumentException) {
Log.d(TAG, "Avoid crash related to Service not registered: ${e.message}")
} }
mBound = false
mContext = null mContext = null
mNetworkService = null
} }
} }