From 35daf3eee023dd4e3ecb47e87b89d16d4b1e5f27 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Mon, 11 Oct 2021 22:48:20 +0200 Subject: [PATCH 1/2] Make AndroidCamera compatible with android API >= 24 by allowing to specify a FILEPROVIDER_AUTHORITY and to get the uri accordingly --- plyer/platforms/android/camera.py | 32 ++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/plyer/platforms/android/camera.py b/plyer/platforms/android/camera.py index 19707bdc7..48404244b 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 + currentActivity = cast('android.app.Activity', PythonActivity.mActivity) + ctx = currentActivity.getApplicationContext() + try: + return FileProvider.getUriForFile(ctx, self.FILEPROVIDER_AUTHORITY, + File(filename)) + except JavaException as exc: + raise Exception( + f'Cannot get a uri for filename {filename} for the Fileprovider ' + f'authority {self.FILEPROVIDER_AUTHORITY}. This probably means that ' + f'FILE_PROVIDER_PATHS is not configured correctly in ' + f'AndroidManifest.xml and/or you need to change the value of ' + f'plyer.camera.FILEPROVIDER_AUTHORITY' + ) + return uri + def instance(): return AndroidCamera() From 67537a4b1a469f99e187c74d20e8b36b75211a30 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Tue, 12 Oct 2021 14:33:42 +0200 Subject: [PATCH 2/2] make flake8 happy --- plyer/platforms/android/camera.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/plyer/platforms/android/camera.py b/plyer/platforms/android/camera.py index 48404244b..30b802bb7 100644 --- a/plyer/platforms/android/camera.py +++ b/plyer/platforms/android/camera.py @@ -64,21 +64,21 @@ def _get_uri_for_file(self, filename): return Uri.parse('file://' + filename) # # For Android >= 10, we need to declare a FileProvider in - # AndroidManifest and set plyer.camera.FILEPROVIDER_AUTHORITY accordingly - currentActivity = cast('android.app.Activity', PythonActivity.mActivity) - ctx = currentActivity.getApplicationContext() + # 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 as exc: + except JavaException: raise Exception( - f'Cannot get a uri for filename {filename} for the Fileprovider ' - f'authority {self.FILEPROVIDER_AUTHORITY}. This probably means that ' - f'FILE_PROVIDER_PATHS is not configured correctly in ' - f'AndroidManifest.xml and/or you need to change the value of ' - f'plyer.camera.FILEPROVIDER_AUTHORITY' + 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' ) - return uri def instance():