Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(dashpay): update image permissions for Android 13 and fix camera #1235

Merged
merged 7 commits into from
Dec 20, 2023
Merged
3 changes: 2 additions & 1 deletion wallet/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@

<!-- dangerous permissions -->
<uses-permission android:name="android.permission.CAMERA" /> <!-- group: CAMERA -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
Comment on lines -20 to +21
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the main change for Android 13.

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
Expand Down
2 changes: 1 addition & 1 deletion wallet/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ android {
compileSdk 33
minSdkVersion 23
targetSdkVersion 33
versionCode project.hasProperty('versionCode') ? project.property('versionCode') as int : 80133
versionCode project.hasProperty('versionCode') ? project.property('versionCode') as int : 90000
versionName project.hasProperty('versionName') ? project.property('versionName') : "5.3-dashpay"
multiDexEnabled true
generatedDensities = ['hdpi', 'xhdpi']
Expand Down
2 changes: 1 addition & 1 deletion wallet/res/layout/activity_settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@

<TextView
style="@style/MenuRowTitle.Internal"
android:text="@string/voting_dash_pay"
android:text="@string/voting_period_active"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/voting_dash_pay_switch"
app:layout_constraintStart_toStartOf="parent"
Expand Down
2 changes: 1 addition & 1 deletion wallet/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@
<string name="quick_vote">Quick Voting</string>
<string name="quick_vote_subtitle">By tapping the "Vote for All" button, you will automatically vote for all of the filtered usernames (%d) that were submitted first</string>
<string name="vote_for_all">Vote for All</string>
<string name="voting_dash_pay">Voting Dash Pay</string>
<string name="voting_period_active">Username Voting Period Active</string>
<string name="there_was_a_network_error">There was a network error, you can try again at no extra cost</string>
<string name="requested_voting_duration">Requested · Voting: 1 Mar – 15 Mar</string>
<string name="cancel_request">Cancel Request</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1025,7 +1025,7 @@ void initViewModel() {
blockchainStateDao.load().observe(this, (blockchainState) -> handleBlockchainStateNotification(blockchainState, mixingStatus));
registerCrowdNodeConfirmedAddressFilter();

FlowExtKt.observe(coinJoinService.getMixingState(), this, (mixingStatus, continuation) -> {
FlowExtKt.observe(coinJoinService.observeMixingState(), this, (mixingStatus, continuation) -> {
handleBlockchainStateNotification(blockchainState, mixingStatus);
return null;
});
Expand Down
66 changes: 40 additions & 26 deletions wallet/src/de/schildbach/wallet/service/CoinJoinService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ import org.bitcoinj.coinjoin.PoolStatus
import org.bitcoinj.coinjoin.callbacks.RequestDecryptedKey
import org.bitcoinj.coinjoin.callbacks.RequestKeyParameter
import org.bitcoinj.coinjoin.listeners.CoinJoinTransactionListener
import org.bitcoinj.coinjoin.utils.CoinJoinTransactionType
import org.bitcoinj.coinjoin.listeners.MixingCompleteListener
import org.bitcoinj.coinjoin.listeners.SessionCompleteListener
import org.bitcoinj.coinjoin.progress.MixingProgressTracker
import org.bitcoinj.coinjoin.utils.CoinJoinManager
import org.bitcoinj.coinjoin.utils.CoinJoinTransactionType
import org.bitcoinj.core.AbstractBlockChain
import org.bitcoinj.core.Coin
import org.bitcoinj.core.Context
Expand Down Expand Up @@ -81,9 +81,9 @@ enum class CoinJoinMode {
* Monitor the status of the CoinJoin Mixing Service
*/
interface CoinJoinService {
val mixingStatus: MixingStatus
val mixingState: Flow<MixingStatus>
val mixingProgress: Flow<Double>
suspend fun getMixingState(): MixingStatus
fun observeMixingState(): Flow<MixingStatus>
fun observeMixingProgress(): Flow<Double>
}

enum class MixingStatus {
Expand Down Expand Up @@ -122,11 +122,11 @@ class CoinJoinMixingService @Inject constructor(
private var sessionCompleteListeners: ArrayList<SessionCompleteListener> = arrayListOf()

var mode: CoinJoinMode = CoinJoinMode.NONE
override var mixingStatus: MixingStatus = MixingStatus.NOT_STARTED
private set
val _mixingState = MutableStateFlow(MixingStatus.NOT_STARTED)
override val mixingState: Flow<MixingStatus>
get() = _mixingState
private val _mixingState = MutableStateFlow(MixingStatus.NOT_STARTED)
private val _progressFlow = MutableStateFlow(0.00)

override suspend fun getMixingState(): MixingStatus = _mixingState.value
override fun observeMixingState(): Flow<MixingStatus> = _mixingState

private val coroutineScope = CoroutineScope(
Executors.newFixedThreadPool(2, ContextPropagatingThreadFactory("coinjoin-pool")).asCoroutineDispatcher()
Expand All @@ -138,16 +138,15 @@ class CoinJoinMixingService @Inject constructor(
private val isBlockChainSet: Boolean
get() = blockChain != null
private var networkStatus: NetworkStatus = NetworkStatus.UNKNOWN
private var isSynced = false
private var hasAnonymizableBalance: Boolean = false

// https://stackoverflow.com/questions/55421710/how-to-suspend-kotlin-coroutine-until-notified
private val updateMutex = Mutex(locked = false)
private val updateMixingStateMutex = Mutex(locked = false)
private var exception: Throwable? = null

override val mixingProgress: Flow<Double>
get() = _progressFlow
private val _progressFlow = MutableStateFlow(0.00)
override fun observeMixingProgress(): Flow<Double> = _progressFlow

init {
blockchainStateProvider.observeNetworkStatus()
Expand All @@ -167,7 +166,12 @@ class CoinJoinMixingService @Inject constructor(
.filterNotNull()
.distinctUntilChanged()
.onEach { blockChainState ->
if (blockChainState.isSynced()) {
val isSynced = blockChainState.isSynced()
if (isSynced != this.isSynced) {
updateState(config.getMode(), hasAnonymizableBalance, networkStatus, isSynced, blockChain)
}
// this will trigger mixing as new blocks are mined and received tx's are confirmed
if (isSynced) {
log.info("coinjoin: new block: ${blockChainState.bestChainHeight}")
updateBalance(walletDataProvider.getWalletBalance())
}
Expand Down Expand Up @@ -204,32 +208,42 @@ class CoinJoinMixingService @Inject constructor(

val hasAnonymizableBalance = anonBalance.isGreaterThan(CoinJoin.getSmallestDenomination())
log.info("coinjoin: mixing can occur: $hasAnonymizableBalance")
updateState(config.getMode(), hasAnonymizableBalance, networkStatus, blockchainStateProvider.getBlockChain())
updateState(
config.getMode(),
hasAnonymizableBalance,
networkStatus,
isSynced,
blockchainStateProvider.getBlockChain()
)
}

private suspend fun updateState(
mode: CoinJoinMode,
hasAnonymizableBalance: Boolean,
networkStatus: NetworkStatus,
isSynced: Boolean,
blockChain: AbstractBlockChain?
) {
updateMutex.lock()
log.info("coinjoin-updateState: ${this.mode}, ${this.hasAnonymizableBalance}, ${this.networkStatus}, ${blockChain != null}")
log.info(
"coinjoin-updateState: ${this.mode}, ${this.hasAnonymizableBalance}, ${this.networkStatus}, ${this.isSynced} ${blockChain != null}"
)
try {
setBlockchain(blockChain)
log.info("coinjoin-updateState: $mode, $hasAnonymizableBalance, $networkStatus, ${blockChain != null}")
log.info(
"coinjoin-updateState: $mode, $hasAnonymizableBalance, $networkStatus, $isSynced, ${blockChain != null}"
)
this.networkStatus = networkStatus
this.mixingStatus = mixingStatus
_mixingState.value = mixingStatus
this.hasAnonymizableBalance = hasAnonymizableBalance
this.isSynced = isSynced
this.mode = mode

if (mode == CoinJoinMode.NONE) {
updateMixingState(MixingStatus.NOT_STARTED)
} else {
configureMixing()
if (hasAnonymizableBalance) {
if (networkStatus == NetworkStatus.CONNECTED && isBlockChainSet) {
if (networkStatus == NetworkStatus.CONNECTED && isBlockChainSet && isSynced) {
updateMixingState(MixingStatus.MIXING)
} else {
updateMixingState(MixingStatus.PAUSED)
Expand All @@ -250,9 +264,8 @@ class CoinJoinMixingService @Inject constructor(
) {
updateMixingStateMutex.lock()
try {

val previousMixingStatus = this.mixingStatus
this.mixingStatus = mixingStatus
val previousMixingStatus = _mixingState.value
_mixingState.value = mixingStatus
log.info("coinjoin-updateMixingState: $previousMixingStatus -> $mixingStatus")

when {
Expand All @@ -273,11 +286,11 @@ class CoinJoinMixingService @Inject constructor(
}

private suspend fun updateBlockChain(blockChain: AbstractBlockChain?) {
updateState(mode, hasAnonymizableBalance, networkStatus, blockChain)
updateState(mode, hasAnonymizableBalance, networkStatus, isSynced, blockChain)
}

private suspend fun updateNetworkStatus(networkStatus: NetworkStatus) {
updateState(mode, hasAnonymizableBalance, networkStatus, blockChain)
updateState(mode, hasAnonymizableBalance, networkStatus, isSynced, blockChain)
}

private suspend fun updateMode(mode: CoinJoinMode) {
Expand All @@ -286,7 +299,7 @@ class CoinJoinMixingService @Inject constructor(
configureMixing()
updateBalance(walletDataProvider.wallet!!.getBalance(Wallet.BalanceType.AVAILABLE))
}
updateState(mode, hasAnonymizableBalance, networkStatus, blockChain)
updateState(mode, hasAnonymizableBalance, networkStatus, isSynced, blockChain)
}

private var mixingProgressTracker: MixingProgressTracker = object : MixingProgressTracker() {
Expand Down Expand Up @@ -347,6 +360,7 @@ class CoinJoinMixingService @Inject constructor(
private fun configureMixing() {
configureMixing(walletDataProvider.getWalletBalance())
}

/** set CoinJoinClientOptions based on CoinJoinMode */
private fun configureMixing(amount: Coin) {
when (mode) {
Expand Down Expand Up @@ -389,7 +403,7 @@ class CoinJoinMixingService @Inject constructor(
clientManager = CoinJoinClientManager(wallet)
coinJoinClientManagers[wallet.description] = clientManager
// this allows mixing to wait for the last transaction to be confirmed
//clientManager.addContinueMixingOnError(PoolStatus.ERR_NO_INPUTS)
// clientManager.addContinueMixingOnError(PoolStatus.ERR_NO_INPUTS)
// wait until the masternode sync system fixes itself
clientManager.addContinueMixingOnError(PoolStatus.ERR_NO_MASTERNODES_DETECTED)
clientManager.setStopOnNothingToDo(true)
Expand Down
Loading
Loading