Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot use saveToPhotoAlbum: true on Android 10 #611

Closed
3 tasks done
AleFons opened this issue Jun 19, 2020 · 52 comments
Closed
3 tasks done

Cannot use saveToPhotoAlbum: true on Android 10 #611

AleFons opened this issue Jun 19, 2020 · 52 comments

Comments

@AleFons
Copy link

AleFons commented Jun 19, 2020

Bug Report

Problem

What is expected to happen?

Using saveToPhotoAlbum: true should allow the user to take a picture and save a backup to the phone's gallery.

What does actually happen?

The plugin instead throws an error on Android 10.

Information

Setting the option to false avoids the problem, but then no backup is made.

Command or Code

I use these options for Camera.getPicture():

annex_options: CameraOptions = {
    destinationType: this.Camera.DestinationType.FILE_URI,
    sourceType: this.Camera.PictureSourceType.PHOTOLIBRARY,
    correctOrientation: false,
    saveToPhotoAlbum: false
  }

Environment, Platform, Device

Android 10, has happened on multiple devices.

Version information

Ionic:

ionic (Ionic CLI) : 4.6.0
Ionic Framework : ionic-angular 3.9.6
@ionic/app-scripts : 3.2.4

Cordova:

cordova (Cordova CLI) : 9.0.0 (cordova-lib@9.0.1)
Cordova Platforms : android 8.1.0, ios 5.0.0
Cordova Plugins : cordova-plugin-ionic-keyboard 2.0.5, cordova-plugin-ionic-webview 2.2.0, (and 18 other plugins)

System:

Android SDK Tools : 26.1.1
NodeJS : v12.16.3
npm : 6.14.4
OS : Linux 4.15

Checklist

  • I searched for existing GitHub issues
  • I updated all Cordova tooling to most recent version
  • I included all the necessary information above
@bartdeveloper
Copy link

I also confirm that issue. On Android 9 all features works great, but after update my device to Android 10 I got "Error capturing image" when flag saveToPhotoAlbum is set to the value true.

Device: Samsung A40

@AleFons
Copy link
Author

AleFons commented Jul 7, 2020

From my understanding, what appears to be happening is that saving to photo album is triggering an access to storage outside the app's permitted storage, as android 10 comes with changes to where the app is permitted to do file operations. It may be possible to fix it with android:requestLegacyExternalStorage="true" but I have had issues with testing that.

@bartdeveloper
Copy link

Unfortunately requestLegacyExternalStorage in config.xml doesn't work.
I tried this code:

<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application" xmlns:android="http://schemas.android.com/apk/res/android"> <application android:requestLegacyExternalStorage="true" /> </edit-config>

And I got:

AAPT: error: attribute android:requestLegacyExternalStorage not found.

@bartdeveloper
Copy link

I downgraded compileSdkVersion from 29 to 28 and now saveToPhotoAlbum works properly.

@AleFons
Copy link
Author

AleFons commented Jul 8, 2020

Even on an Android 10 phone?

@bartdeveloper
Copy link

Yes, I tested this solution on Samsung A40 with Android 10. When I had Android 9 then all camera features worked properly with setting compileSdkVersion=29, but after upgrade to Android 10 I had to downgrade compileSdkVersion.
Of course if you utilize features from Android 10, then this solution isn't correct.

@kriskhoavu
Copy link

@bartdeveloper Appreciate if you could share your git repo link.

@breautek
Copy link
Contributor

breautek commented Jul 8, 2020

Looks like API 29 requires Scoped Locations

There are two current workarounds:

  1. Reduce the target sdk to 28, which can be done via the android-targetSdkVersion preference.
  2. Use the requestLegacyExternalStorage flag. Which can be added using the <edit-config>. This flag requires you to target/compile for API 29 (the default in cordova-android@9)

I'm not familiar with this plugin's codebase, but it looks like MediaStore is already used, and that's what the Android docs suggest that we need to use. So further investigation is going to be required to determine what the actual problem is.

The plugin instead throws an error on Android 10.

It would be nice to know exactly what that error is, and perhaps stacktrace.

@isamuAsial
Copy link

The commit e9aba07 is bad and causes this issue.

@erisu
Copy link
Member

erisu commented Jul 14, 2020

@isamuAsial That commit is not officially released and only exists in master.

I would recommend using 4.1.0 which had been voted on and official released for production use. 4.1.0 release does not contain that commit.

@AleFons
Copy link
Author

AleFons commented Jul 14, 2020

Looks like API 29 requires Scoped Locations

There are two current workarounds:

  1. Reduce the target sdk to 28, which can be done via the android-targetSdkVersion preference.
  2. Use the requestLegacyExternalStorage flag. Which can be added using the <edit-config>. This flag requires you to target/compile for API 29 (the default in cordova-android@9)

I'm not familiar with this plugin's codebase, but it looks like MediaStore is already used, and that's what the Android docs suggest that we need to use. So further investigation is going to be required to determine what the actual problem is.

The plugin instead throws an error on Android 10.

It would be nice to know exactly what that error is, and perhaps stacktrace.

I had white screen issues when trying to use that flag.

@jwasnoggin
Copy link

It would be nice to know exactly what that error is, and perhaps stacktrace.

This is the stacktrace that I got in the logcat:

java.io.FileNotFoundException: open failed: EACCES (Permission denied)
    at android.os.ParcelFileDescriptor.openInternal(ParcelFileDescriptor.java:315)
    at android.os.ParcelFileDescriptor.open(ParcelFileDescriptor.java:220)
    at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:1498)
    at android.content.ContentResolver.openOutputStream(ContentResolver.java:1227)
    at android.content.ContentResolver.openOutputStream(ContentResolver.java:1203)
    at org.apache.cordova.camera.CameraLauncher.writeUncompressedImage(CameraLauncher.java:866)
    at org.apache.cordova.camera.CameraLauncher.writeUncompressedImage(CameraLauncher.java:902)
    at org.apache.cordova.camera.CameraLauncher.processResultFromCamera(CameraLauncher.java:508)
    at org.apache.cordova.camera.CameraLauncher.onActivityResult(CameraLauncher.java:806)
    at org.apache.cordova.CordovaInterfaceImpl.onActivityResult(CordovaInterfaceImpl.java:159)
    at org.apache.cordova.CordovaActivity.onActivityResult(CordovaActivity.java:361)

I was ultimately able to resolve the error using the requestLegacyExternalStorage flag.

@anatolykazantsev
Copy link

anatolykazantsev commented Aug 24, 2020

@isamuAsial That commit is not officially released and only exists in master.

I would recommend using 4.1.0 which had been voted on and official released for production use. 4.1.0 release does not contain that commit.

We're using 4.1.0 and we have exactly same problem on Android 10 devices. The stacktrace is same as provided by @jwasnoggin above. So it seems production version is affected as well.

Cordova CLI: 10.0.0
Cordova platform: android 9.0.0

@olidotjpeg
Copy link

I am having this same issue on API SDK 29, tried adding this snippet to my Android platform in the config.xml file.

<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application" xmlns:android="http://schemas.android.com/apk/res/android"> 
    <application android:requestLegacyExternalStorage="true" /> 
</edit-config>

Which either causes the app to crash when I accept permissions or do nothing at all.

Cordova CLI: 10.0.0
Cordova Platform : Android 9.0.0
As I mentioned above I am building for Android 29

@jsBiztech
Copy link

Hello,
Is there any solution for this yet?
I have tried solutions given in this, but the issue persists.

@pc-partner
Copy link

Hello,
Is there any solution for this yet?
I have tried solutions given in this, but the issue persists.

Same here.

@wifisher
Copy link

Not sure if this is related or not, but v5.0.0 of the plugin fails for me as well with saveToPhotoAlbum set true. For me, it is also failing on my Android 8 test device with the following stack trace:

 java.io.FileNotFoundException: content:/com.fi.pmp.cordova.plugin.camera.provider/cache_files/.Pic.jpg (No such file or directory)
    at java.io.FileInputStream.open0(Native Method)
    at java.io.FileInputStream.open(FileInputStream.java:200)
    at java.io.FileInputStream.<init>(FileInputStream.java:150)
    at java.io.FileInputStream.<init>(FileInputStream.java:103)
    at org.apache.cordova.camera.CameraLauncher.writeUncompressedImage(CameraLauncher.java:906)
    at org.apache.cordova.camera.CameraLauncher.processResultFromCamera(CameraLauncher.java:503)
    at org.apache.cordova.camera.CameraLauncher.onActivityResult(CameraLauncher.java:808)
    at org.apache.cordova.CordovaInterfaceImpl.onActivityResult(CordovaInterfaceImpl.java:159)
    at org.apache.cordova.CordovaActivity.onActivityResult(CordovaActivity.java:361)
    at android.app.Activity.dispatchActivityResult(Activity.java:7599)
    at android.app.ActivityThread.deliverResults(ActivityThread.java:4487)
    at android.app.ActivityThread.handleSendResult(ActivityThread.java:4534)
    at android.app.ActivityThread.-wrap20(Unknown Source:0)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1752)
    at android.os.Handler.dispatchMessage(Handler.java:105)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6944)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

It appears that the source URI has a content: scheme instead of a file: scheme that writeUncompressedImage() expects.

I was able to get it working by changing line 903 of CameraLauncher.java from:

FileInputStream fis = new FileInputStream(FileHelper.stripFileProtocol(src.toString()));

to

InputStream fis = this.cordova.getActivity().getContentResolver().openInputStream(src);

openInputStream() is documented to accept both file: and content: schemes, so this change should handle both cases.

With this change, saveToPhotoAlbum works again on this Android 8 device. I haven't had a chance to test on any other devices yet.

@alex96gm
Copy link

Hello,
Is there any solution for this yet?
I have tried solutions given in this, but the issue persists.

Same here. Any solution or workarounds for Android 10

@wifisher
Copy link

With my above change, it is now working for me on my Android 10 device using "cordova-android": "^9.0.0" and "cordova-plugin-camera": "^5.0.0".

The options that I am passing in to getPicture() are:

            sourceType: navigator.camera.PictureSourceType.CAMERA
            destinationType: navigator.camera.DestinationType.FILE_URI,,
            encodingType: navigator.camera.EncodingType.JPEG,
            quality: 75,
            saveToPhotoAlbum: true,
            targetWidth: 2048,
            targetHeight: 2048

@jsBiztech
Copy link

Hey @wifisher ,
Have you tried setting targetSDKVersion to 29?
Thanks!

@wifisher
Copy link

Isn't the targetSDKVersion set to 29 by cordova-android 9.0.0?

@jsBiztech
Copy link

Isn't the targetSDKVersion set to 29 by cordova-android 9.0.0?

I am unaware of this. Can you check whether it is 29 or not?

@wifisher
Copy link

According to https://cordova.apache.org/announcements/2020/06/29/cordova-android-9.0.0.html the default targetSDKVersion is 29 with cordova-android 9.0.0.

I did a test by setting the version in config.xml with the following line:
<preference name="android-targetSdkVersion" value="29"/>

I was able to take a picture and have it appear in the gallery.

@olidotjpeg
Copy link

The app I am working on we also have <preference name="android-targetSdkVersion" value="29" /> enabled, but it still fails when the savePhotoToAlbum is enabled. Only way to fix is force it to sdk28 which is not preferred :/

@wifisher
Copy link

You can test my fix by making the change to CameraLauncher.java that I mentioned above. Test by making the change to the file at this location: platforms/android/app/src/main/java/org/apache/cordova/camera. Then build and run.

If it works, then your problem is the same as mine. I wouldn't build a release with this change hacked in, but it would be useful to know if it is the same problem or not.

It's a small change, but it would be nice to see it come out in a 5.0.1 version of the camera plugin.

PieterVanPoyer added a commit to PieterVanPoyer/cordova-plugin-camera that referenced this issue Sep 29, 2020
…om camera - Android

- saveToPhotoAlbum feature fixed by taken into count content - uri. (writeUncompressedImage method) ( see: apache#611 (comment) )
- make saveToPhotoAlbum future proof by using the MediaStore to insert the taken image
- made a method to calculate the compressFormat based on the encodingType (JPEG or PNG)
- layout of the performCrop method is adjusted
- removed unused rotate variable inside processResultFromGallery method
@PieterVanPoyer
Copy link
Contributor

PieterVanPoyer commented Sep 29, 2020

@wifisher I did made a change to the code. I've read your suggestion of the content uri.

You can test the changes with next commands.

npx cordova plugin remove cordova-plugin-camera
npx cordova plugin add https://github.com/PieterVanPoyer/cordova-plugin-camera.git#bugfix/issue-341-save-to-photo-gallery

Can you test this? After testing I could make a PR for this.

Another remark: It should be saved to the photo album, if you take a picture with the camera.
This issue is about selecting from the gallery and saving a copy to the gallery of it. ( sourceType: this.Camera.PictureSourceType.PHOTOLIBRARY, ) But that's another issue. The issue you are refering to is #577 or #341

Kind regards.

@wifisher
Copy link

@PieterVanPoyer I installed your plugin and it appears to be working correctly for me.

@basvdijk
Copy link

I "solved" this issue by using Capacitor instead of Cordova using https://capacitorjs.com/docs/apis/camera

@olidotjpeg
Copy link

@PieterVanPoyer I can confirm that your fix is also working for me.

@jsBiztech
Copy link

jsBiztech commented Oct 1, 2020

@PieterVanPoyer ,
I have following config:

Ionic Framework : ionic-angular 3.9.2
@ionic/app-scripts : 3.2.4
Cordova CLI : 8.1.2
Cordova Platforms : android 7.1.4, ios 4.5.5
cordova-plugin-camera : 4.0.3

Should updating Cordova-plugin-camera to 5.0 resolve this without changing the Cordova version?
Thanks!

@PieterVanPoyer
Copy link
Contributor

I did make a Pull Request to solve the issue with saveToPhotoAlbum and the camera. #669
But this code is not in the master.
You could try (for testing purposes) to install my fork (for now).

npx cordova plugin remove cordova-plugin-camera
npx cordova plugin add https://github.com/PieterVanPoyer/cordova-plugin-camera.git#bugfix/issue-341-save-to-photo-gallery

I don't think updating (or installing the fork) is possible without updating the Cordova CLI and cordova android version. (Current version of the cli is 10, I believe.)

Kind regards

breautek pushed a commit that referenced this issue Oct 17, 2020
* GH-341 - GH-577 Fixed the Save Photo To Album starting from camera - Android

- saveToPhotoAlbum feature fixed by taken into count content - uri. (writeUncompressedImage method) ( see: #611 (comment) )
- make saveToPhotoAlbum future proof by using the MediaStore to insert the taken image
- made a method to calculate the compressFormat based on the encodingType (JPEG or PNG)
- layout of the performCrop method is adjusted
- removed unused rotate variable inside processResultFromGallery method

* Add extra VO class to the plugin.xml

* added package declaration to new VO

* GH-341 - GH-577 #669 (comment) listen to review
@HarelM
Copy link

HarelM commented Oct 28, 2020

I'm using the latest version of this plugin from master after the above merge but it seems that it doesn't work with android 10, even if I set requestLegacyExternalStorage to true (using the latest cordova-file-plugin adds this to the manifest).
When I'm trying to open the camera to take a picture I get to the following code:

if (takePicturePermission && saveAlbumPermission) {
            takePicture(returnType, encodingType);
        } else if (saveAlbumPermission && !takePicturePermission) {
            PermissionHelper.requestPermission(this, TAKE_PIC_SEC, Manifest.permission.CAMERA);
        } else if (!saveAlbumPermission && takePicturePermission) {
/// ---> I'm getting here which doesn't do anything in android 10...
            PermissionHelper.requestPermissions(this, TAKE_PIC_SEC,
                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE});
        } else {
            PermissionHelper.requestPermissions(this, TAKE_PIC_SEC, permissions);
        }

Has anyone else got to this point? Am I missing something? Should I just remove the saveToPhoto album?
Any help would be appreciated.
Cordova 10, cordova-android 9.0, of course.

@PieterVanPoyer
Copy link
Contributor

PieterVanPoyer commented Oct 28, 2020

@HarelM I was able to reproduce it.

In my testsetup I removed the <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> - tag of the AndroidManifest.xml.
Is this tag present in your AndroidManifest?

image

When I remove this line <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />, I can reproduce the behaviour.
What is the content of your AndroidManifest.xml?

Kind regards
Pieter

@jsBiztech
Copy link

Hello @PieterVanPoyer ,

I have used the latest Camera plugin version and I am facing an issue in which I am unable to upload files from the google drive.

I have created an issue in the file plugin repo, but haven't got a reply. If you can look into it.
Here is the link: apache/cordova-plugin-file#432

Thanks.

@HarelM
Copy link

HarelM commented Oct 29, 2020

@PieterVanPoyer Thanks! Seems like this permission is now missing, I have no idea why, I see it on both the camera plugin plugin.xml and file plugin plugin.xml with the same annotation:

<config-file target="AndroidManifest.xml" parent="/*">
            <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        </config-file>

But it doesn't get to the manifest.xml file as it used to.
Since I upgraded to Cordova 10 the entire environment had become shaky and I need to place stuff in different places in the 'package.json` file to make the app compile. So it might be another bug I'm just not sure where to report it...

@PieterVanPoyer
Copy link
Contributor

@HarelM indeed normally the permission must be set by cordova itself.
Because the WRITE_EXTERNAL_STORAGE must be declared in the manifest, else the user is unable to allow it later. The reason is, that the permission holds a high risk and it must be whitelisted. [ https://developer.android.com/reference/android/Manifest.permission.html#WRITE_EXTERNAL_STORAGE ]
It is indeed correctly declared in the plugin.xml.
Does removing the platform and plugin and afterwards reïnstalling it solve the problem?

Can you reproduce it in a blank Cordova 10 project in anyway, with just the camera plugin included?
If yes, then you could make a new issue for the camera plugin.

@HarelM
Copy link

HarelM commented Oct 29, 2020

I'm not sure I can reproduce it on a blank project. but my project is open source and the CI build machine is always a clean start.
The turn point from my point of view is upgrading the cordova cli version and not the camera plugin...
I have opened some issues in the cordova-fetch and cordova-cli project but didn't get any response yet...

@HarelM
Copy link

HarelM commented Oct 29, 2020

BTW @PieterVanPoyer, after fixing all the permission issues and build issues I still don't see the image I take in the photo gallery so I'm not sure the latest version (after the #669 PR merged here) does fix this bug in all android versions...
Let me know if you want me to test anything specific...
Package.json and config.xml can be found here:
https://github.com/IsraelHikingMap/Site/tree/master/IsraelHiking.Web

@PieterVanPoyer
Copy link
Contributor

@HarelM I won't be able to test every Android device offcourse.

But just to be curious, is the taken picture returned to your app?
So it is only the save to gallery that fails, or do you receive an error in your javascript. If yes, what is the error?

Do you use DATA_URI or FILE_URI as type?
In what Android version does it fail? Android 10, Android 11, Android 9, ... ?

@HarelM
Copy link

HarelM commented Oct 30, 2020

I'm using android 9.
The image is returned to the client without any error as far as I understand.
I'm using DATA_URI as can be seen here.
@PieterVanPoyer I fully understand you won't be able to test every android device, this is why I'm reporting this, so I can help in testing.
You can see here the configuration:
https://github.com/IsraelHikingMap/Site/blob/master/IsraelHiking.Web/sources/application/directives/image-capture.directive.ts#L49

@PieterVanPoyer
Copy link
Contributor

Originally, there was an error thrown and no image was returned.

You could try to test with next repo: https://github.com/PieterVanPoyer/cordova-camera-plugin-testing-app/tree/master
If you set the camera plugin to the master, you could try this repo.

Then maybe we can pinpoint the issue. Do you test on an emulator or on a real device?

@HarelM
Copy link

HarelM commented Oct 30, 2020

My bad, I now see the photo I took in the Pictures folder (not the camera folder, which is what google photos is showing).
Thanks for the fix! Sorry for miss-leading...

@PieterVanPoyer
Copy link
Contributor

No problem. We figured out the permission issue.
Cheers!

@jsBiztech
Copy link

Hello @PieterVanPoyer ,

I have used the latest Camera plugin version and I am facing an issue in which I am unable to upload files from the google drive.

I have created an issue in the file plugin repo, but haven't got a reply. If you can look into it.
Here is the link: apache/cordova-plugin-file#432

Thanks.

Can anyone help me on this?

@PieterVanPoyer
Copy link
Contributor

@AleFons is this issue still happening with the latest released version? If not, feel free to close this issue.

@Franco-Alejandro
Copy link

Any updates on this?

@byronigoe
Copy link

Can't speak for @AleFons, but I encountered the same issue, and the latest version resolved it for me.

@AleFons
Copy link
Author

AleFons commented Feb 18, 2021

The latest version has solved it for me too. I believe the issue has been solved with Cordova 10.

@PieterVanPoyer
Copy link
Contributor

@AleFons nice, maybe you should close this issue then? Kind regards Pieter

@AleFons AleFons closed this as completed Feb 18, 2021
@mfsikalyan
Copy link

From my understanding, what appears to be happening is that saving to photo album is triggering an access to storage outside the app's permitted storage, as android 10 comes with changes to where the app is permitted to do file operations. It may be possible to fix it with android:requestLegacyExternalStorage="true" but I have had issues with testing that.

This worked for me, it is a great solution

@mballav
Copy link

mballav commented Jul 24, 2021

I have this issue on Android 11. None of the above solutions work! I upgraded to cordova-android 10. That didn't help either. Anyone tried the solutions on Android 11?

@Christoffleroux
Copy link

I have this issue on Android 11. None of the above solutions work! I upgraded to cordova-android 10. That didn't help either. Anyone tried the solutions on Android 11?

Same Here Does not work on Android 10 or 11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests