From 135864f2887dc31c34edfd108b8af8d66f556b6a Mon Sep 17 00:00:00 2001 From: DisabledAbel <196466003+DisabledAbel@users.noreply.github.com> Date: Mon, 10 Aug 2026 22:39:40 +0000 Subject: [PATCH 1/2] Add browser redirect link option on update signature verification/download failures When an automatic update check or installation fails (e.g. due to signature certificate mismatch), display an option to open the update release page or APK link directly in the device's web browser, enabling manual downloading and installation. --- .../java/com/tunnelguard/app/UpdateManager.kt | 20 ++++++++++++++++-- .../app/update/UpdateDialogScreen.kt | 21 ++++++++++++++++++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/tunnelguard/app/UpdateManager.kt b/app/src/main/java/com/tunnelguard/app/UpdateManager.kt index 654a11f..054add0 100644 --- a/app/src/main/java/com/tunnelguard/app/UpdateManager.kt +++ b/app/src/main/java/com/tunnelguard/app/UpdateManager.kt @@ -8,6 +8,7 @@ import android.net.Uri import android.os.Build import android.provider.Settings import androidx.core.content.FileProvider +import com.tunnelguard.app.update.UpdateRepository import java.io.File import java.io.FileOutputStream import java.io.IOException @@ -424,12 +425,27 @@ class UpdateManager( } fun showUpdateErrorDialog(errorMessage: String) { - androidx.appcompat.app.AlertDialog.Builder(activity) + val repo = UpdateRepository.getInstance(activity) + val targetUrl = repo.getCachedReleaseUrl()?.ifBlank { null } ?: repo.getCachedApkUrl() + + val builder = androidx.appcompat.app.AlertDialog.Builder(activity) .setTitle("Update Check Failed") .setMessage("Could not check for updates or download update.\n\nDetails: $errorMessage") .setPositiveButton("OK") { dialog, _ -> dialog.dismiss() } - .show() + + if (!targetUrl.isNullOrBlank()) { + builder.setNeutralButton("Open in Browser") { dialog, _ -> + dialog.dismiss() + try { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(targetUrl)) + activity.startActivity(intent) + } catch (e: Exception) { + config.addLog("Failed to open browser for update: ${e.message}") + } + } + } + builder.show() } } diff --git a/app/src/main/java/com/tunnelguard/app/update/UpdateDialogScreen.kt b/app/src/main/java/com/tunnelguard/app/update/UpdateDialogScreen.kt index 8c3b59c..9fe70b4 100644 --- a/app/src/main/java/com/tunnelguard/app/update/UpdateDialogScreen.kt +++ b/app/src/main/java/com/tunnelguard/app/update/UpdateDialogScreen.kt @@ -72,7 +72,26 @@ fun UpdateDialogScreen(state: UpdateUiState, onUpdateNow: () -> Unit, onExitApp: state.errorMessage?.let { Text(it, color = MaterialTheme.colorScheme.error, modifier = Modifier.padding(top = 12.dp)) } Spacer(Modifier.height(16.dp)) Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(12.dp)) { - Button(onClick = onUpdateNow, enabled = !state.isDownloading, modifier = Modifier.weight(1f).height(56.dp).focusRequester(focusRequester)) { Text("Update Now") } + val context = LocalContext.current + val browserUrl = state.releaseUrl.ifBlank { state.apkUrl.orEmpty() } + + if (!state.errorMessage.isNullOrBlank() && browserUrl.isNotBlank()) { + Button( + onClick = { + try { + val intent = android.content.Intent(android.content.Intent.ACTION_VIEW, android.net.Uri.parse(browserUrl)) + context.startActivity(intent) + } catch (e: Exception) { + // ignore browser launch failures gracefully + } + }, + modifier = Modifier.weight(1f).height(56.dp) + ) { + Text("Open in Browser") + } + } else { + Button(onClick = onUpdateNow, enabled = !state.isDownloading, modifier = Modifier.weight(1f).height(56.dp).focusRequester(focusRequester)) { Text("Update Now") } + } OutlinedButton(onClick = onExitApp, enabled = !state.isDownloading, modifier = Modifier.weight(1f).height(56.dp)) { Text("Exit App") } } } From 84f5db91569ce11b735b6504c25148f21b797587 Mon Sep 17 00:00:00 2001 From: DisabledAbel <196466003+DisabledAbel@users.noreply.github.com> Date: Mon, 10 Aug 2026 23:33:17 +0000 Subject: [PATCH 2/2] Enhance update failure browser redirect option with logging and error UI feedback In UpdateDialogScreen, catch and log exceptions during browser launch attempts, showing a Toast failure notification to the user instead of silently ignoring the issue. Also update UpdateManager to offer a fallback browser redirection when update download/verification checks fail. --- .../java/com/tunnelguard/app/update/UpdateDialogScreen.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/tunnelguard/app/update/UpdateDialogScreen.kt b/app/src/main/java/com/tunnelguard/app/update/UpdateDialogScreen.kt index 9fe70b4..68a7f12 100644 --- a/app/src/main/java/com/tunnelguard/app/update/UpdateDialogScreen.kt +++ b/app/src/main/java/com/tunnelguard/app/update/UpdateDialogScreen.kt @@ -82,7 +82,9 @@ fun UpdateDialogScreen(state: UpdateUiState, onUpdateNow: () -> Unit, onExitApp: val intent = android.content.Intent(android.content.Intent.ACTION_VIEW, android.net.Uri.parse(browserUrl)) context.startActivity(intent) } catch (e: Exception) { - // ignore browser launch failures gracefully + val config = com.tunnelguard.app.TunnelGuardConfig(context) + config.addLog("Failed to open browser for update: ${e.message}", "ERROR") + android.widget.Toast.makeText(context, "Failed to launch browser. Please open the link manually.", android.widget.Toast.LENGTH_LONG).show() } }, modifier = Modifier.weight(1f).height(56.dp)