Skip to content

Commit

Permalink
fix lockscreen passcode
Browse files Browse the repository at this point in the history
  • Loading branch information
polstianka committed Oct 8, 2024
1 parent f732194 commit f89f2ea
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 82 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.tonapps.wallet.data.passcode

import android.content.Context
import androidx.biometric.BiometricPrompt
import com.tonapps.wallet.data.settings.SettingsRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.withContext

class LockScreen(
private val passcodeManager: PasscodeManager,
private val settingsRepository: SettingsRepository
) {

sealed class State {
data object None: State()
data object Input: State()
data object Biometric: State()
data object Error: State()
}

private val _stateFlow = MutableStateFlow<State?>(null)
val stateFlow = _stateFlow.asStateFlow().filterNotNull()

fun init() {
if (!settingsRepository.lockScreen) {
hide()
} else if (settingsRepository.biometric) {
_stateFlow.value = State.Biometric
} else {
_stateFlow.value = State.Input
}
}

private fun hide() {
_stateFlow.value = State.None
}

private fun error() {
_stateFlow.value = State.Error
}

suspend fun check(context: Context, code: String) = withContext(Dispatchers.IO) {
val valid = passcodeManager.isValid(context, code)
if (valid) {
hide()
} else {
error()
}
}

fun biometric(result: BiometricPrompt.AuthenticationResult) {
hide()
}

fun reset() {

}

}
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package com.tonapps.wallet.data.passcode

import android.content.Context
import androidx.biometric.BiometricPrompt
import com.tonapps.extensions.logError
import com.tonapps.wallet.data.account.AccountRepository
import com.tonapps.wallet.data.passcode.dialog.PasscodeDialog
import com.tonapps.wallet.data.rn.RNLegacy
import com.tonapps.wallet.data.settings.SettingsRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import uikit.navigation.Navigation
import java.util.concurrent.atomic.AtomicBoolean

class PasscodeManager(
private val accountRepository: AccountRepository,
Expand All @@ -21,14 +24,34 @@ class PasscodeManager(
private val scope: CoroutineScope
) {

private val lockscreen = LockScreen(this, settingsRepository)

val lockscreenFlow: Flow<LockScreen.State>
get() = lockscreen.stateFlow

init {
scope.launch(Dispatchers.IO) {
if (rnLegacy.isRequestMigration()) {
helper.reset()
}
lockscreen.init()
}
}

fun lockscreenBiometric(result: BiometricPrompt.AuthenticationResult) {
lockscreen.biometric(result)
}

fun deleteAll() {
scope.launch {
reset()
}
}

fun lockscreenCheck(context: Context, code: String) {
scope.launch { lockscreen.check(context, code) }
}

suspend fun hasPinCode(): Boolean = withContext(Dispatchers.IO) {
if (helper.hasPinCode) {
true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fun Context.safeExternalOpenUri(uri: Uri) {
val intent = Intent(Intent.ACTION_VIEW, uri)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
} catch (e: Exception) {
} catch (e: Throwable) {
debugToast(e)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ import com.tonapps.wallet.data.settings.SettingsRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import org.koin.androidx.viewmodel.dsl.viewModelOf
import org.koin.core.module.dsl.factoryOf
import org.koin.core.module.dsl.singleOf
import org.koin.core.module.dsl.viewModelOf
import org.koin.dsl.module

val koinModel = module {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ class MainSwipeRefreshLayout @JvmOverloads constructor(

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
setProgressViewOffset(true, topPadding, topPadding + 42.dp)
setProgressViewOffset(true, topPadding, topPadding + 40.dp)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.concurrent.atomic.AtomicBoolean
Expand Down Expand Up @@ -69,7 +70,7 @@ class EventsViewModel(
}

autoRefreshJob = viewModelScope.launch(Dispatchers.IO) {
while (true) {
while (isActive) {
checkAutoRefresh()
delay(35.seconds)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,15 @@ package com.tonapps.tonkeeper.ui.screen.root

import android.content.Intent
import android.content.res.Configuration
import android.content.res.Resources
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatDelegate
import androidx.biometric.BiometricPrompt
import androidx.core.app.ActivityCompat
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope
import com.tonapps.extensions.toUriOrNull
import com.tonapps.tonkeeper.App
import com.tonapps.tonkeeper.extensions.isDarkMode
Expand All @@ -35,7 +31,9 @@ import com.tonapps.tonkeeperx.R
import com.tonapps.wallet.api.entity.TokenEntity
import com.tonapps.wallet.data.account.entities.WalletEntity
import com.tonapps.wallet.data.core.Theme
import com.tonapps.wallet.data.passcode.LockScreen
import com.tonapps.wallet.data.passcode.PasscodeBiometric
import com.tonapps.wallet.data.passcode.PasscodeManager
import com.tonapps.wallet.data.passcode.ui.PasscodeView
import com.tonapps.wallet.data.rn.RNLegacy
import com.tonapps.wallet.data.settings.SettingsRepository
Expand All @@ -59,6 +57,7 @@ class RootActivity: BaseWalletActivity() {

private val legacyRN: RNLegacy by inject()
private val settingsRepository by inject<SettingsRepository>()
private val passcodeManager by inject<PasscodeManager>()

private lateinit var uiHandler: Handler

Expand All @@ -84,7 +83,9 @@ class RootActivity: BaseWalletActivity() {

lockView = findViewById(R.id.lock)
lockPasscodeView = findViewById(R.id.lock_passcode)
lockPasscodeView.doOnCheck = ::checkPasscode
lockPasscodeView.doOnCheck = {
passcodeManager.lockscreenCheck(this, it)
}

lockSignOut = findViewById(R.id.lock_sign_out)
lockSignOut.setOnClickListener { signOutAll() }
Expand All @@ -98,11 +99,36 @@ class RootActivity: BaseWalletActivity() {

collectFlow(viewModel.hasWalletFlow) { init(it) }
collectFlow(viewModel.eventFlow) { event(it) }
collectFlow(viewModel.passcodeFlow, ::passcodeFlow)
collectFlow(passcodeManager.lockscreenFlow, ::pinState)

App.applyConfiguration(resources.configuration)
}

private fun pinState(state: LockScreen.State) {
if (state == LockScreen.State.None) {
lockView.visibility = View.GONE
lockPasscodeView.setSuccess()
} else if (state == LockScreen.State.Error) {
lockPasscodeView.setError()
} else {
lockView.visibility = View.VISIBLE
if (state is LockScreen.State.Biometric) {
PasscodeBiometric.showPrompt(this, getString(Localization.app_name), object : BiometricPrompt.AuthenticationCallback() {

override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
passcodeManager.lockscreenBiometric(result)
}

override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
toast(Localization.authorization_required)
}
})
}
}
}

private fun createOrGetViewModel(): RootViewModel {
if (cachedRootViewModel == null) {
cachedRootViewModel = viewModel<RootViewModel>()
Expand Down Expand Up @@ -148,36 +174,6 @@ class RootActivity: BaseWalletActivity() {
}
}

private fun passcodeFlow(config: RootViewModel.Passcode) {
if (!config.show) {
lockView.visibility = View.GONE
return
}
lockView.visibility = View.VISIBLE
if (config.biometric) {
PasscodeBiometric.showPrompt(this, getString(Localization.app_name), object : BiometricPrompt.AuthenticationCallback() {

override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
lockView.visibility = View.GONE
}

override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
toast(Localization.authorization_required)
}
})
}
}

private fun checkPasscode(code: String) {
viewModel.checkPasscode(this, code).catch {
lockPasscodeView.setError()
}.onEach {
lockPasscodeView.setSuccess()
}.launchIn(lifecycleScope)
}

override fun setContentView(layoutResID: Int) {
super.setContentView(R.layout.activity_root)
}
Expand Down Expand Up @@ -233,6 +229,7 @@ class RootActivity: BaseWalletActivity() {
builder.setMessage(Localization.sign_out_all_description)
builder.setNegativeButton(Localization.sign_out) {
viewModel.signOut()
passcodeManager.deleteAll()
setIntroFragment()
}
builder.setPositiveButton(Localization.cancel)
Expand Down
Loading

0 comments on commit f89f2ea

Please sign in to comment.