brarcher / loyalty-card-locker

Stores your barcode-based store/loyalty cards on your phone
GNU General Public License v3.0
171 stars 29 forks source link

Error while exporting to CSV #349

Closed cazzoo closed 4 years ago

cazzoo commented 4 years ago

Hello, I just installed the app and got all my card scanned properly. Thank you for your hard work

This app work fine so far but I tried to export (backup) my all card list and got error (see attached screenshot) Screenshot_20200126-121851_Loyalty_Card_Keychain

This is the only blocking feature I experience so far.

TheLastProject commented 4 years ago

Odd, exporting works fine on my device. Just to get the obvious possibility out of the way, did you maybe accidentally deny the app permission to "Storage"?

image

cazzoo commented 4 years ago

It's all authorized (sorry for system language) Screenshot_20200126-131223_Contr�leur_autorisations Autorisé means authorized

Note that I'm using Android Q

TheLastProject commented 4 years ago

Do you happen to have adb configured on your computer? Connecting your Android device and running adb logcat -s LoyaltyCardLocker, followed by hitting the export button on your phone, should give us more logs of what went wrong.

cazzoo commented 4 years ago

It seems related to permission issue...

--------- beginning of system --------- beginning of crash --------- beginning of main 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: Unable to export file 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: java.io.FileNotFoundException: /storage/emulated/0/LoyaltyCardKeychain.csv: open failed: EACCES (Permission denied) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at libcore.io.IoBridge.open(IoBridge.java:496) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at java.io.FileOutputStream.(FileOutputStream.java:235) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at java.io.FileOutputStream.(FileOutputStream.java:186) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at protect.card_locker.ImportExportTask.performExport(ImportExportTask.java:87) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at protect.card_locker.ImportExportTask.doInBackground(ImportExportTask.java:130) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at protect.card_locker.ImportExportTask.doInBackground(ImportExportTask.java:20) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at android.os.AsyncTask$3.call(AsyncTask.java:378) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at java.util.concurrent.FutureTask.run(FutureTask.java:266) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at java.lang.Thread.run(Thread.java:919) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at libcore.io.Linux.open(Native Method) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at libcore.io.ForwardingOs.open(ForwardingOs.java:167) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at libcore.io.BlockGuardOs.open(BlockGuardOs.java:252) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at libcore.io.ForwardingOs.open(ForwardingOs.java:167) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7296) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: at libcore.io.IoBridge.open(IoBridge.java:482) 01-26 17:14:07.732 2945 2988 E LoyaltyCardLocker: ... 11 more 01-26 17:14:07.732 2945 2988 I LoyaltyCardLocker: Export of '/storage/emulated/0/LoyaltyCardKeychain.csv' result: false 01-26 17:14:07.777 2945 2945 I LoyaltyCardLocker: Export Complete

It seems perhaps automatically restricted by OS with android Q. Is there a way to specify another export location?

brarcher commented 4 years ago

Hm. The app currently finds the location of the external storage and tries to write there:

    private final File sdcardDir = Environment.getExternalStorageDirectory();
    private final File exportFile = new File(sdcardDir, "LoyaltyCardKeychain.csv");

Might it be possible that the device does not have a writable external storage dir and everything is internal storage? Not sure.

As for the question:

Is there a way to specify another export location?

the app does not currently support this, but it is a possibility. I've received this request once already from someone else who reported that exporting to file does not work. Maybe this is a feature that needs to be added in the near future.

cazzoo commented 4 years ago

Might it be possible that the device does not have a writable external storage dir and everything is internal storage? Not sure. Hi! That definitely can be an option, my current device doesn't provide external sdcard slot...

Also, the ability to chose another export location was thought as a workaround.

Both should be acceptable as long export feature works. Nothing in a hurry, I can live without it for several weeks, I just want to create a backup in case I need to restore.

I can alpha test if you are not able to reproduce in emulator or if you need any extra feedbacks

brarcher commented 4 years ago

Just to set expectations, adding the feature will probably be left up to an interested contributor from the community. I'll review any potential change, but probably will not be able to get to adding it myself for now.

At one point I added support for a file picker in the Video Transcoder app, and that used NoNonsense-FilePicker. There is a warning in its README suggesting to use the Android native file picker for external SD cards, so maybe the Android native picker is good enough? A potential solution would need to work on both typical Android distributions which include Google's apps and distributions without.

cazzoo commented 4 years ago

I fully understand your point here. While I checked about the path exists I can validate that the virtual folder to external dir does exists. I also tried to create a txt file in this directory using a folder explorer application and it work as expected. I'll try to create the file using adb asap to see results from another source

TheLastProject commented 4 years ago

@cazzoo I just made #352 which uses the file manager to pick an export location instead of using the fixed location. Can you please test if that works for you? If needed, I can create an .apk for you.

cazzoo commented 4 years ago

Thanks, I'll test this asap

cazzoo commented 4 years ago

I didn't got it working on both my device or an emulated device. I guess your proposed solution might fit the need but I didn't had chance to validate it and lose my data trying to deploy on my device :/ My bad

TheLastProject commented 4 years ago

I'm not completely sure what you mean. In what way did you "not get it working"? Maybe I can help by providing an .apk with an altered app name so that it will install next to the official version? My laptop doesn't really have enough RAM to run the emulators so I can't test on Android 10 myself easily (but maybe @brarcher can)

cazzoo commented 4 years ago

I tried to compile it by myself (checkout the fork and switched to the correct branch), got app built and deployed to the emulator with an alternate export feature but it was weird, not working as described : export button was the same, but when failing I had a button on the right side of the modal giving the ability to save elsewhere. I tried this button but didn't had chance to save elsewhere since I had no play account linked nor any file browser. Then from Android studio I had chance to select my device as target, which I did, and that was the bad idea I had :X

In the other hand, reading your message and the PR once again, it makes me confused and I now believe it was not the intended feature...

I'd be glad to test this out if you find a way to generate this apk with an alternate name

TheLastProject commented 4 years ago

The idea behind my change was: if Android doesn't let us just save it, maybe opening the internal file browser and ask the user to select a location will allow us to save it.

I've changed the applicationId in app/build.gradle to make Android see this as another app so you can test this without losing your data. You'll have to create some nonsense data for testing exporting in this modified version. See attached app-debug.zip. Of course, seeing how you seem to know how to use Android Studio, you could also do this yourself by just changing the applicationId :)

Could you next time take some screenshots maybe? It's easier to make sure we both understand things the same way :)

app-debug.zip

cazzoo commented 4 years ago

It's working like a charm ! :100: Let me post saving flow : Screenshot_20200129-184142_Syst�me_Android Then Screenshot_20200129-184152_Fichiers And finally Screenshot_20200129-184159_Loyalty_Card_Keychain

Note the path is not using the virtual external sdcard (as previously used by default). That's probably the root cause of that permission issue

Kudos for this change @TheLastProject , I think it could be merged to master branch

cazzoo commented 4 years ago

The only thing I don't get is the "send..." button (Envoyer...). Maybe it's a native Android feature for the modal?

TheLastProject commented 4 years ago

The send button was there already, probably coded by @brarcher, if you press it it should try to open an email or whatever app to share the file with so you can easily send the backup to another device.

Anyway, very glad to hear it works! :)

cazzoo commented 4 years ago

For info, here's is the default path (working with this feature) if I select it using my internal file browser : Screenshot_20200129-183953_Loyalty_Card_Keychain

We can see it mounting volume differently than the default path provided by Android function. Perhaps this is due to storage encryption...