diff --git a/app/src/main/java/protect/card_locker/MainActivity.kt b/app/src/main/java/protect/card_locker/MainActivity.kt index 352fbcf1c..0fc441cd8 100644 --- a/app/src/main/java/protect/card_locker/MainActivity.kt +++ b/app/src/main/java/protect/card_locker/MainActivity.kt @@ -533,29 +533,41 @@ class MainActivity : CatimaAppCompatActivity(), CardAdapterListener { private fun importFile(data: Uri?, receivedType: String) { lifecycleScope.launch { val parseResultList: MutableList = withContext(Dispatchers.IO) { - when { - receivedType.startsWith("image/") -> - Utils.retrieveBarcodesFromImage(this@MainActivity, data) - receivedType == "application/pdf" -> - Utils.retrieveBarcodesFromPdf(this@MainActivity, data) - receivedType == "application/vnd.apple.pkpass" || - receivedType == "application/vnd-com.apple.pkpass" -> - Utils.retrieveBarcodesFromPkPass(this@MainActivity, data) - // FIXME: espass is not pkpass - // However, several users stated in https://github.com/CatimaLoyalty/Android/issues/2197 that the formats are extremely similar to the point they could rename an .espass file to .pkpass and have it imported - // So it makes sense to "unofficially" treat it as a PKPASS for now, even though not completely correct - receivedType == "application/vnd.espass-espass" -> - Utils.retrieveBarcodesFromPkPass(this@MainActivity, data) - receivedType == "application/vnd.apple.pkpasses" -> - Utils.retrieveBarcodesFromPkPasses(this@MainActivity, data) - else -> { - Log.e(TAG, "Wrong mime-type") - return@withContext null + try { + when { + receivedType.startsWith("image/") -> + Utils.retrieveBarcodesFromImage(this@MainActivity, data) + + receivedType == "application/pdf" -> + Utils.retrieveBarcodesFromPdf(this@MainActivity, data) + + receivedType == "application/vnd.apple.pkpass" || + receivedType == "application/vnd-com.apple.pkpass" -> + Utils.retrieveBarcodesFromPkPass(this@MainActivity, data) + // FIXME: espass is not pkpass + // However, several users stated in https://github.com/CatimaLoyalty/Android/issues/2197 that the formats are extremely similar to the point they could rename an .espass file to .pkpass and have it imported + // So it makes sense to "unofficially" treat it as a PKPASS for now, even though not completely correct + receivedType == "application/vnd.espass-espass" -> + Utils.retrieveBarcodesFromPkPass(this@MainActivity, data) + + receivedType == "application/vnd.apple.pkpasses" -> + Utils.retrieveBarcodesFromPkPasses(this@MainActivity, data) + + else -> { + Log.e(TAG, "Wrong mime-type") + return@withContext null + } } + } catch (e: Exception) { + Log.e(TAG, "Parsing failed: $e"); + e.printStackTrace(); + Utils.showToast(this@MainActivity, R.string.errorReadingFile, Toast.LENGTH_LONG); + return@withContext null; } } ?: return@launch if (parseResultList.isEmpty()) { + Utils.showToast(this@MainActivity, R.string.noBarcodeFound, Toast.LENGTH_LONG); finish() return@launch } diff --git a/app/src/main/java/protect/card_locker/PkpassesParser.kt b/app/src/main/java/protect/card_locker/PkpassesParser.kt index f56e05eaa..3c1a34fb4 100644 --- a/app/src/main/java/protect/card_locker/PkpassesParser.kt +++ b/app/src/main/java/protect/card_locker/PkpassesParser.kt @@ -22,6 +22,8 @@ class PkpassesParser(context: Context, uri: Uri?) { throw IOException(context.getString(R.string.errorReadingFile)) } + var hasPkpassFiles = false + try { mContext.contentResolver.openInputStream(uri).use { inputStream -> ZipInputStream(inputStream).use { zipInputStream -> @@ -42,6 +44,9 @@ class PkpassesParser(context: Context, uri: Uri?) { // Ignore non-pkpass files if (!localFileHeader.fileName.endsWith(".pkpass")) continue + // Mark as found + hasPkpassFiles = true + // Extract .pkpass (.zip) inside .pkpasses to cache directory val tempFileName = "pkpassparser_" + System.currentTimeMillis() + "_" + localFileHeader.fileName val tempFile = Utils.copyToTempFile(mContext, zipInputStream, tempFileName) @@ -61,6 +66,11 @@ class PkpassesParser(context: Context, uri: Uri?) { } catch (e: Exception) { throw e } + + if (!hasPkpassFiles) { + Log.d(TAG, "No pkpass files found") + throw IOException(mContext.getString(R.string.errorReadingFile)) + } } fun getPkpassParsers(): ArrayList { diff --git a/app/src/main/java/protect/card_locker/ScanActivity.kt b/app/src/main/java/protect/card_locker/ScanActivity.kt index fad13b96d..22e882bf6 100644 --- a/app/src/main/java/protect/card_locker/ScanActivity.kt +++ b/app/src/main/java/protect/card_locker/ScanActivity.kt @@ -331,7 +331,14 @@ class ScanActivity : CatimaAppCompatActivity() { Utils.parseSetBarcodeActivityResult(requestCode, resultCode, intent, this@ScanActivity) withContext(Dispatchers.Main) { + if (parseResultList == null) { + Utils.showToast(this@ScanActivity, R.string.errorReadingFile, Toast.LENGTH_LONG) + setScannerActive(true) + return@withContext + } + if (parseResultList.isEmpty()) { + Utils.showToast(this@ScanActivity, R.string.noBarcodeFound, Toast.LENGTH_LONG) setScannerActive(true) return@withContext } diff --git a/app/src/main/java/protect/card_locker/Utils.java b/app/src/main/java/protect/card_locker/Utils.java index e8527d2c0..0c9dbf313 100644 --- a/app/src/main/java/protect/card_locker/Utils.java +++ b/app/src/main/java/protect/card_locker/Utils.java @@ -121,7 +121,7 @@ public class Utils { static final int BITMAP_SIZE_BIG = 1600; // Displays the toast immediately on the main UI loop, or asks Android to display it there otherwise. - static private void showToast(Context context, int message, int duration) { + static public void showToast(Context context, int message, int duration) { if (Looper.myLooper() == Looper.getMainLooper()) { Toast.makeText(context, message, duration).show(); } else { @@ -160,50 +160,35 @@ public class Utils { tileLetterFontSize, pixelSize, pixelSize, backgroundColor, ForegroundColorHelper.Companion.needsDarkForeground(backgroundColor) ? Color.BLACK : Color.WHITE); } - static public List retrieveBarcodesFromImage(Context context, Uri uri) { + static public List retrieveBarcodesFromImage(Context context, Uri uri) throws FileNotFoundException { Log.i(TAG, "Received image file with possible barcode"); if (uri == null) { - Log.e(TAG, "Uri did not contain any data"); - showToast(context, R.string.errorReadingImage, Toast.LENGTH_LONG); - return new ArrayList<>(); + throw new FileNotFoundException("Uri did not contain any data"); } Bitmap bitmap; try { bitmap = retrieveImageFromUri(context, uri); } catch (IOException e) { - Log.e(TAG, "Error getting data from image file"); - e.printStackTrace(); - showToast(context, R.string.errorReadingImage, Toast.LENGTH_LONG); - return new ArrayList<>(); + throw new IllegalArgumentException("Error reading image file", e); } - List barcodesFromBitmap = getBarcodesFromBitmap(bitmap); - - if (barcodesFromBitmap.isEmpty()) { - Log.i(TAG, "No barcode found in image file"); - showToast(context, R.string.noBarcodeFound, Toast.LENGTH_LONG); - } - - return barcodesFromBitmap; + // Returns barcodes or an empty list if nothing found + return getBarcodesFromBitmap(bitmap); } - static public List retrieveBarcodesFromPkPass(Context context, Uri uri) { + static public List retrieveBarcodesFromPkPass(Context context, Uri uri) throws FileNotFoundException { Log.i(TAG, "Received Pkpass file with possible barcode"); if (uri == null) { - Log.e(TAG, "Pkpass did not contain any data"); - showToast(context, R.string.errorReadingFile, Toast.LENGTH_LONG); - return new ArrayList<>(); + throw new FileNotFoundException("Uri did not contain any data"); } PkpassParser pkpassParser; try { pkpassParser = new PkpassParser(context, uri); } catch (Exception e) { - Log.e(TAG, "Error reading pkpass file", e); - showToast(context, R.string.errorReadingFile, Toast.LENGTH_LONG); - return new ArrayList<>(); + throw new IllegalArgumentException("Error reading pkpass file", e); } List locales = pkpassParser.listLocales(); @@ -211,9 +196,7 @@ public class Utils { try { return Collections.singletonList(new ParseResult(ParseResultType.FULL, pkpassParser.toLoyaltyCard(null))); } catch (Exception e) { - Log.e(TAG, "Error calling toLoyaltyCard on pkpass file", e); - showToast(context, R.string.errorReadingFile, Toast.LENGTH_LONG); - return new ArrayList<>(); + throw new IllegalArgumentException("Error calling toLoyaltyCard on pkpass file", e); } } @@ -223,9 +206,7 @@ public class Utils { try { parseResult = new ParseResult(ParseResultType.FULL, pkpassParser.toLoyaltyCard(locale)); } catch (Exception e) { - Log.e(TAG, "Error calling toLoyaltyCard on pkpass file", e); - showToast(context, R.string.errorReadingFile, Toast.LENGTH_LONG); - return new ArrayList<>(); + throw new IllegalArgumentException("Error calling toLoyaltyCard on pkpass file", e); } parseResult.setNote(locale); parseResultList.add(parseResult); @@ -234,21 +215,17 @@ public class Utils { return parseResultList; } - static public List retrieveBarcodesFromPkPasses(Context context, Uri uri) { + static public List retrieveBarcodesFromPkPasses(Context context, Uri uri) throws FileNotFoundException { Log.i(TAG, "Received Pkpasses file with possible barcode"); if (uri == null) { - Log.e(TAG, "Pkpasses did not contain any data"); - showToast(context, R.string.errorReadingFile, Toast.LENGTH_LONG); - return new ArrayList<>(); + throw new FileNotFoundException("Uri did not contain any data"); } PkpassesParser pkpassesParser; try { pkpassesParser = new PkpassesParser(context, uri); } catch (Exception e) { - Log.e(TAG, "Error reading pkpasses file", e); - showToast(context, R.string.errorReadingFile, Toast.LENGTH_LONG); - return new ArrayList<>(); + throw new IllegalArgumentException("Error reading pkpasses file", e); } List parseResultList = new ArrayList<>(); @@ -260,9 +237,7 @@ public class Utils { try { parseResult = new ParseResult(ParseResultType.FULL, pkpassParser.toLoyaltyCard(null)); } catch (Exception e) { - Log.e(TAG, "Error calling toLoyaltyCard on pkpass file", e); - showToast(context, R.string.errorReadingFile, Toast.LENGTH_LONG); - return new ArrayList<>(); + throw new IllegalArgumentException("Error calling toLoyaltyCard on pkpass file", e); } parseResult.setNote(String.format(context.getString(R.string.cardWithNumber), i+1)); parseResultList.add(parseResult); @@ -271,9 +246,7 @@ public class Utils { try { parseResult = new ParseResult(ParseResultType.FULL, pkpassParser.toLoyaltyCard(locale)); } catch (Exception e) { - Log.e(TAG, "Error calling toLoyaltyCard on pkpass file", e); - showToast(context, R.string.errorReadingFile, Toast.LENGTH_LONG); - return new ArrayList<>(); + throw new IllegalArgumentException("Error calling toLoyaltyCard on pkpass file", e); } parseResult.setNote(String.format(context.getString(R.string.cardWithNumberAndLocale), i+1, locale)); parseResultList.add(parseResult); @@ -286,12 +259,10 @@ public class Utils { return parseResultList; } - static public List retrieveBarcodesFromPdf(Context context, Uri uri) { + static public List retrieveBarcodesFromPdf(Context context, Uri uri) throws FileNotFoundException { Log.i(TAG, "Received PDF file with possible barcode"); if (uri == null) { - Log.e(TAG, "Uri did not contain any data"); - showToast(context, R.string.errorReadingFile, Toast.LENGTH_LONG); - return new ArrayList<>(); + throw new FileNotFoundException("Uri did not contain any data"); } ParcelFileDescriptor parcelFileDescriptor = null; @@ -326,8 +297,7 @@ public class Utils { } } } catch (IOException e) { - Log.e(TAG, "Error reading PDF file", e); - showToast(context, R.string.errorReadingFile, Toast.LENGTH_LONG); + throw new IllegalArgumentException("Error reading PDF file", e); } finally { // Resource handling if (renderer != null) { @@ -342,10 +312,7 @@ public class Utils { } } - if (barcodesFromPdfPages.isEmpty()) { - Log.i(TAG, "No barcode found in pdf file"); - showToast(context, R.string.noBarcodeFound, Toast.LENGTH_LONG); - } + // Returns barcodes or an empty list if nothing found return barcodesFromPdfPages; } @@ -360,6 +327,7 @@ public class Utils { * @param context * @return List */ + @Nullable static public List parseSetBarcodeActivityResult(int requestCode, int resultCode, Intent intent, Context context) { String contents; String format; @@ -368,34 +336,35 @@ public class Utils { return new ArrayList<>(); } - if (requestCode == Utils.BARCODE_IMPORT_FROM_IMAGE_FILE) { - return retrieveBarcodesFromImage(context, intent.getData()); - } - - if (requestCode == Utils.BARCODE_IMPORT_FROM_PDF_FILE) { - return retrieveBarcodesFromPdf(context, intent.getData()); - } - - if (requestCode == Utils.BARCODE_IMPORT_FROM_PKPASS_FILE) { - Uri intentData = intent != null ? intent.getData() : null; - - if (intentData == null) { - Log.e(TAG, "Uri did not contain any data"); - showToast(context, R.string.errorReadingFile, Toast.LENGTH_LONG); - return new ArrayList<>(); + try { + if (requestCode == Utils.BARCODE_IMPORT_FROM_IMAGE_FILE) { + return retrieveBarcodesFromImage(context, intent.getData()); } - try { - if (Objects.equals(context.getContentResolver().getType(intentData), "application/vnd.apple.pkpasses")) { - return retrieveBarcodesFromPkPasses(context, intentData); + if (requestCode == Utils.BARCODE_IMPORT_FROM_PDF_FILE) { + return retrieveBarcodesFromPdf(context, intent.getData()); + } + + if (requestCode == Utils.BARCODE_IMPORT_FROM_PKPASS_FILE) { + Uri intentData = intent != null ? intent.getData() : null; + + if (intentData == null) { + throw new FileNotFoundException("Uri did not contain any data"); } - return retrieveBarcodesFromPkPass(context, intentData); - } catch (Exception e) { - Log.e(TAG, "Error reading pkpass file", e); - showToast(context, R.string.errorReadingFile, Toast.LENGTH_LONG); - return new ArrayList<>(); + // Mime type info is not always available. So we're going to first guess it's a pkpass file and if that fails, try pkpasses + try { + return retrieveBarcodesFromPkPass(context, intentData); + } catch (Exception e) { + Log.e(TAG, "Error reading pkpass file, attempting as pkpasses file", e); + return retrieveBarcodesFromPkPasses(context, intentData); + } } + } catch (Exception e) { + // Return null instead of an empty list to differentiate between error or no result + Log.e(TAG, "Parsing failed: " + e); + e.printStackTrace(); + return null; } if (requestCode == Utils.BARCODE_SCAN || requestCode == Utils.SELECT_BARCODE_REQUEST) {