Add proactive QR code size validation and checks

- Add isContentSuitableForQRCode() helper function with 2900 character limit
- Check QR code size before attempting generation in both activities
- Prevent fullscreen QR viewer from launching when data is too large
- Use conservative 2900 character limit (vs theoretical 2953 max)
- Add size validation in both PolycentricBackupActivity and QRCodeFullscreenActivity
- Improve user experience by failing fast with clear error messages

This ensures QR codes are only generated when they have a reasonable
chance of success, and prevents unnecessary attempts to generate
QR codes that are too large for reliable scanning.
This commit is contained in:
Trevor
2025-08-19 10:59:16 -05:00
parent 31f0109438
commit a20ebd49a4
2 changed files with 33 additions and 1 deletions
@@ -89,6 +89,11 @@ class PolycentricBackupActivity : AppCompatActivity() {
val bundle = createExportBundle() val bundle = createExportBundle()
Logger.i(TAG, "Export bundle created, length: ${bundle.length}") Logger.i(TAG, "Export bundle created, length: ${bundle.length}")
// Check if bundle is suitable for QR code
if (!isContentSuitableForQRCode(bundle)) {
throw Exception("Data too big for QR code generation")
}
val dimension = TypedValue.applyDimension( val dimension = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 200f, resources.displayMetrics TypedValue.COMPLEX_UNIT_DIP, 200f, resources.displayMetrics
).toInt() ).toInt()
@@ -104,7 +109,7 @@ class PolycentricBackupActivity : AppCompatActivity() {
_buttonShare.visibility = View.VISIBLE _buttonShare.visibility = View.VISIBLE
_buttonCopy.visibility = View.VISIBLE _buttonCopy.visibility = View.VISIBLE
// Add click listener to open QR code in fullscreen // Add click listener to open QR code in fullscreen (only if QR generation succeeded)
_imageQR.setOnClickListener { _imageQR.setOnClickListener {
val intent = QRCodeFullscreenActivity.createIntent(this@PolycentricBackupActivity, _exportBundle) val intent = QRCodeFullscreenActivity.createIntent(this@PolycentricBackupActivity, _exportBundle)
startActivity(intent) startActivity(intent)
@@ -151,7 +156,18 @@ class PolycentricBackupActivity : AppCompatActivity() {
}; };
} }
private fun isContentSuitableForQRCode(content: String): Boolean {
// QR Code Version 40 (177x177) with L error correction can hold ~2953 characters
// We use a conservative limit of 2900 characters to ensure reliable generation
return content.length <= 2900
}
private fun generateQRCode(content: String, width: Int, height: Int): Bitmap { private fun generateQRCode(content: String, width: Int, height: Int): Bitmap {
// Check if content is too large for QR code generation
if (!isContentSuitableForQRCode(content)) {
throw Exception("Data too big for QR code generation")
}
val hints = java.util.EnumMap<EncodeHintType, Any>(EncodeHintType::class.java) val hints = java.util.EnumMap<EncodeHintType, Any>(EncodeHintType::class.java)
hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.M hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.M
hints[EncodeHintType.MARGIN] = 1 hints[EncodeHintType.MARGIN] = 1
@@ -47,6 +47,11 @@ class QRCodeFullscreenActivity : AppCompatActivity() {
// Generate QR code bitmap from text // Generate QR code bitmap from text
qrText?.let { text -> qrText?.let { text ->
try { try {
// Check if content is suitable for QR code
if (!isContentSuitableForQRCode(text)) {
throw Exception("Data too big for QR code generation")
}
val dimension = TypedValue.applyDimension( val dimension = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 300f, resources.displayMetrics TypedValue.COMPLEX_UNIT_DIP, 300f, resources.displayMetrics
).toInt() ).toInt()
@@ -73,7 +78,18 @@ class QRCodeFullscreenActivity : AppCompatActivity() {
} }
} }
private fun isContentSuitableForQRCode(content: String): Boolean {
// QR Code Version 40 (177x177) with L error correction can hold ~2953 characters
// We use a conservative limit of 2900 characters to ensure reliable generation
return content.length <= 2900
}
private fun generateQRCode(content: String, width: Int, height: Int): Bitmap { private fun generateQRCode(content: String, width: Int, height: Int): Bitmap {
// Check if content is too large for QR code generation
if (!isContentSuitableForQRCode(content)) {
throw Exception("Data too big for QR code generation")
}
val hints = java.util.EnumMap<EncodeHintType, Any>(EncodeHintType::class.java) val hints = java.util.EnumMap<EncodeHintType, Any>(EncodeHintType::class.java)
hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.M hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.M
hints[EncodeHintType.MARGIN] = 1 hints[EncodeHintType.MARGIN] = 1