From 5e84901ca94952cbccb4d3c295c41719a87a9c21 Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Mon, 20 Apr 2026 14:20:12 -0300 Subject: [PATCH] Refactor IntentUtils to improve performance and safety in result handling - Wrap the result processing logic in `onAccept` within a try-finally block to ensure `onLoading(false)` is always called - Move history database insertion and permission acceptance into nested coroutines to avoid blocking the main flow - Refactor application entity initialization to reduce unnecessary package manager calls - Optimize GZIP compression implementation using `use` blocks for better resource management - Simplify access to the Main activity and clipboard operations using `withContext(Dispatchers.Main)` - Ensure `finishAndRemoveTask()` is called more reliably after processing intents --- .../nostrsigner/service/IntentUtils.kt | 319 +++++++++--------- 1 file changed, 161 insertions(+), 158 deletions(-) diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt b/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt index d167fb58..82b5d438 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt @@ -58,6 +58,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext object IntentUtils { private val _intents = MutableStateFlow>(persistentListOf()) @@ -670,176 +671,178 @@ object IntentUtils { ) { onLoading(true) Amber.instance.applicationIOScope.launch { - val database = Amber.instance.getDatabase(account.npub) - val historyDatabase = Amber.instance.getHistoryDatabase(account.npub) - val savedApplication = database.dao().getByKey(key) - val localAppName = - if (packageName != null) { - try { - val info = context.packageManager.getApplicationInfo(packageName, 0) - context.packageManager.getApplicationLabel(info).toString() - } catch (_: Exception) { - null + try { + val database = Amber.instance.getDatabase(account.npub) + val savedApplication = database.dao().getByKey(key) + + val application = + savedApplication ?: run { + val localAppName = + if (packageName != null && appName == null) { + try { + val info = context.packageManager.getApplicationInfo(packageName, 0) + context.packageManager.getApplicationLabel(info).toString() + } catch (_: Exception) { + null + } + } else { + appName + } + ApplicationWithPermissions( + application = ApplicationEntity( + key = key, + name = appName ?: localAppName ?: "", + relays = emptyList(), + url = "", + icon = "", + description = "", + pubKey = account.hexKey, + isConnected = true, + secret = "", + useSecret = false, + signPolicy = account.signPolicy, + closeApplication = shouldCloseApplication != false, + deleteAfter = deleteAfter, + lastUsed = TimeUtils.now(), + ), + permissions = mutableListOf(), + ) } - } else { - appName - } - - val application = - savedApplication ?: ApplicationWithPermissions( - application = ApplicationEntity( - key = key, - name = appName ?: localAppName ?: "", - relays = emptyList(), - url = "", - icon = "", - description = "", - pubKey = account.hexKey, - isConnected = true, - secret = "", - useSecret = false, - signPolicy = account.signPolicy, - closeApplication = shouldCloseApplication != false, - deleteAfter = deleteAfter, - lastUsed = TimeUtils.now(), - ), - permissions = mutableListOf(), - ) - application.application.isConnected = true - - if (signPolicy != null) { - AmberUtils.configureSignPolicy(application, signPolicy, key, permissions) - } - - if (rememberType != RememberType.NEVER) { - AmberUtils.acceptPermission( - application = application, - key = key, - type = intentData.type, - kind = kind, - rememberType = rememberType, - relay = relay, - encryptedData = intentData.encryptedData, - decryptTypeScope = decryptTypeScope, - ) - } - - if (intentData.type == SignerType.GET_PUBLIC_KEY) { application.application.isConnected = true - shouldCloseApplication?.let { - application.application.closeApplication = it - } - if (!application.permissions.any { it.type == SignerType.GET_PUBLIC_KEY.toString() }) { - application.permissions.add( - ApplicationPermissionsEntity( - null, - key, - SignerType.GET_PUBLIC_KEY.toString(), - null, - true, - RememberType.ALWAYS.screenCode, - Long.MAX_VALUE / 1000, - 0, - ), - ) - } - } - if (packageName != null) { - database.dao().insertApplicationWithPermissions(application) - historyDatabase.dao().addHistory( - HistoryEntity( - 0, - key, - intentData.type.toString(), - kind, - TimeUtils.now(), - true, - content = when (intentData.type) { - SignerType.SIGN_EVENT -> event - SignerType.NIP04_DECRYPT, - SignerType.NIP44_DECRYPT, - SignerType.DECRYPT_ZAP_EVENT, - -> value - else -> intentData.data - }, - ), - account.npub, - ) + if (signPolicy != null) { + AmberUtils.configureSignPolicy(application, signPolicy, key, permissions) + } + + if (rememberType != RememberType.NEVER) { + Amber.instance.applicationIOScope.launch { + AmberUtils.acceptPermission( + application = application, + key = key, + type = intentData.type, + kind = kind, + rememberType = rememberType, + relay = relay, + encryptedData = intentData.encryptedData, + decryptTypeScope = decryptTypeScope, + ) + } + } - val intent = Intent() - intent.putExtra("signature", value) - intent.putExtra("result", value) - intent.putExtra("id", intentData.id) - intent.putExtra("event", event) if (intentData.type == SignerType.GET_PUBLIC_KEY) { - intent.putExtra("package", BuildConfig.APPLICATION_ID) + shouldCloseApplication?.let { + application.application.closeApplication = it + } + if (!application.permissions.any { it.type == SignerType.GET_PUBLIC_KEY.toString() }) { + application.permissions.add( + ApplicationPermissionsEntity( + null, + key, + SignerType.GET_PUBLIC_KEY.toString(), + null, + true, + RememberType.ALWAYS.screenCode, + Long.MAX_VALUE / 1000, + 0, + ), + ) + } } - val activity = Amber.instance.getMainActivity() - activity?.setResult(RESULT_OK, intent) - onRemoveIntentData(listOf(intentData), IntentResultType.REMOVE) - activity?.intent = null - activity?.finishAndRemoveTask() - } else if (!intentData.callBackUrl.isNullOrBlank()) { - if (intentData.returnType == ReturnType.SIGNATURE) { - val intent = Intent(Intent.ACTION_VIEW) - intent.data = (intentData.callBackUrl + Uri.encode(value)).toUri() - context.startActivity(intent) + + if (packageName != null) { + database.dao().insertApplicationWithPermissions(application) + val historyDatabase = Amber.instance.getHistoryDatabase(account.npub) + Amber.instance.applicationIOScope.launch { + historyDatabase.dao().addHistory( + HistoryEntity( + 0, + key, + intentData.type.toString(), + kind, + TimeUtils.now(), + true, + content = when (intentData.type) { + SignerType.SIGN_EVENT -> event + SignerType.NIP04_DECRYPT, + SignerType.NIP44_DECRYPT, + SignerType.DECRYPT_ZAP_EVENT, + -> value + + else -> intentData.data + }, + ), + account.npub, + ) + } + + val intent = Intent() + intent.putExtra("signature", value) + intent.putExtra("result", value) + intent.putExtra("id", intentData.id) + intent.putExtra("event", event) + if (intentData.type == SignerType.GET_PUBLIC_KEY) { + intent.putExtra("package", BuildConfig.APPLICATION_ID) + } + Amber.instance.getMainActivity()?.setResult(RESULT_OK, intent) + } else if (!intentData.callBackUrl.isNullOrBlank()) { + if (intentData.returnType == ReturnType.SIGNATURE) { + val intent = Intent(Intent.ACTION_VIEW) + intent.data = (intentData.callBackUrl + Uri.encode(value)).toUri() + context.startActivity(intent) + } else { + if (intentData.compression == CompressionType.GZIP) { + // Compress the string using GZIP + val encodedString = ByteArrayOutputStream().use { bos -> + GZIPOutputStream(bos).use { gzos -> + gzos.write(event.toByteArray()) + } + Base64.getEncoder().encodeToString(bos.toByteArray()) + } + + val intent = Intent(Intent.ACTION_VIEW) + intent.data = (intentData.callBackUrl + Uri.encode("Signer1$encodedString")).toUri() + context.startActivity(intent) + } else { + val intent = Intent(Intent.ACTION_VIEW) + intent.data = (intentData.callBackUrl + Uri.encode(event)).toUri() + context.startActivity(intent) + } + } } else { - if (intentData.compression == CompressionType.GZIP) { - // Compress the string using GZIP - val byteArrayOutputStream = ByteArrayOutputStream() - val gzipOutputStream = GZIPOutputStream(byteArrayOutputStream) - gzipOutputStream.write(event.toByteArray()) - gzipOutputStream.close() + val result = + if (intentData.returnType == ReturnType.SIGNATURE) { + value + } else { + event + } + val message = + if (intentData.returnType == ReturnType.SIGNATURE) { + context.getString(R.string.signature_copied_to_the_clipboard) + } else { + context.getString(R.string.event_copied_to_the_clipboard) + } - // Convert the compressed data to Base64 - val compressedData = byteArrayOutputStream.toByteArray() - val encodedString = Base64.getEncoder().encodeToString(compressedData) - val intent = Intent(Intent.ACTION_VIEW) - intent.data = (intentData.callBackUrl + Uri.encode("Signer1$encodedString")).toUri() - context.startActivity(intent) - } else { - val intent = Intent(Intent.ACTION_VIEW) - intent.data = (intentData.callBackUrl + Uri.encode(event)).toUri() - context.startActivity(intent) + withContext(Dispatchers.Main) { + clipboardManager.setClipEntry( + ClipEntry( + ClipData.newPlainText("", result), + ), + ) + + Toast.makeText( + context, + message, + Toast.LENGTH_SHORT, + ).show() } } onRemoveIntentData(listOf(intentData), IntentResultType.REMOVE) - val activity = Amber.instance.getMainActivity() - activity?.intent = null - activity?.finishAndRemoveTask() - } else { - val result = - if (intentData.returnType == ReturnType.SIGNATURE) { - value - } else { - event - } - val message = - if (intentData.returnType == ReturnType.SIGNATURE) { - context.getString(R.string.signature_copied_to_the_clipboard) - } else { - context.getString(R.string.event_copied_to_the_clipboard) - } - - Amber.instance.applicationIOScope.launch(Dispatchers.Main) { - clipboardManager.setClipEntry( - ClipEntry( - ClipData.newPlainText("", result), - ), - ) - - Toast.makeText( - context, - message, - Toast.LENGTH_SHORT, - ).show() + Amber.instance.getMainActivity()?.let { + it.intent = null + it.finishAndRemoveTask() } - onRemoveIntentData(listOf(intentData), IntentResultType.REMOVE) - val activity = Amber.instance.getMainActivity() - activity?.intent = null - activity?.finishAndRemoveTask() + } finally { + onLoading(false) } } }