diff --git a/plyer/platforms/android/camera.py b/plyer/platforms/android/camera.py index 19707bdc..30b802bb 100644 --- a/plyer/platforms/android/camera.py +++ b/plyer/platforms/android/camera.py @@ -1,7 +1,7 @@ import android import android.activity from os import remove -from jnius import autoclass, cast +from jnius import autoclass, cast, JavaException from plyer.facades import Camera from plyer.platforms.android import activity @@ -9,10 +9,14 @@ PythonActivity = autoclass('org.kivy.android.PythonActivity') MediaStore = autoclass('android.provider.MediaStore') Uri = autoclass('android.net.Uri') +File = autoclass('java.io.File') +FileProvider = autoclass('android.support.v4.content.FileProvider') class AndroidCamera(Camera): + FILEPROVIDER_AUTHORITY = None + def _take_picture(self, on_complete, filename=None): assert(on_complete is not None) self.on_complete = on_complete @@ -20,7 +24,7 @@ def _take_picture(self, on_complete, filename=None): android.activity.unbind(on_activity_result=self._on_activity_result) android.activity.bind(on_activity_result=self._on_activity_result) intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) - uri = Uri.parse('file://' + filename) + uri = self._get_uri_for_file(filename) parcelable = cast('android.os.Parcelable', uri) intent.putExtra(MediaStore.EXTRA_OUTPUT, parcelable) activity.startActivityForResult(intent, 0x123) @@ -32,7 +36,7 @@ def _take_video(self, on_complete, filename=None): android.activity.unbind(on_activity_result=self._on_activity_result) android.activity.bind(on_activity_result=self._on_activity_result) intent = Intent(MediaStore.ACTION_VIDEO_CAPTURE) - uri = Uri.parse('file://' + filename) + uri = self._get_uri_for_file(filename) parcelable = cast('android.os.Parcelable', uri) intent.putExtra(MediaStore.EXTRA_OUTPUT, parcelable) @@ -54,6 +58,28 @@ def _remove(self, fn): except OSError: pass + def _get_uri_for_file(self, filename): + if self.FILEPROVIDER_AUTHORITY is None: + # default behavior, backward-compatible: works with Android <= 9 + return Uri.parse('file://' + filename) + # + # For Android >= 10, we need to declare a FileProvider in + # AndroidManifest and set plyer.camera.FILEPROVIDER_AUTHORITY + # accordingly + curActivity = cast('android.app.Activity', PythonActivity.mActivity) + ctx = curActivity.getApplicationContext() + try: + return FileProvider.getUriForFile(ctx, self.FILEPROVIDER_AUTHORITY, + File(filename)) + except JavaException: + raise Exception( + f'Cannot get a uri for filename {filename} for the ' + f'Fileprovider authority {self.FILEPROVIDER_AUTHORITY}. This ' + f'probably means that FILE_PROVIDER_PATHS is not configured ' + f'correctly in AndroidManifest.xml and/or you need to change ' + f'the value of plyer.camera.FILEPROVIDER_AUTHORITY' + ) + def instance(): return AndroidCamera()