Mercurial > libervia-desktop-kivy
comparison cagou/core/platform_/android.py @ 400:71f51198478c
android: handle runtime permissions:
- some mandatory permissions are requested on Cagou start, Cagou won't start at all and
display a warning message if they are not granted (we request 5 times before showing the
warning)
- transfer plugin can now use "android_permissions" in plugin_info, to indicate what is
necessary. The permissions will then be requested, and the plugin widget won't be shown
if they are not granted (and a warning not will then be displayed)
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 09 Feb 2020 23:47:29 +0100 |
parents | a5457241c17f |
children | 788e05d1e2bf |
comparison
equal
deleted
inserted
replaced
399:672880661797 | 400:71f51198478c |
---|---|
25 from pathlib import Path | 25 from pathlib import Path |
26 import shutil | 26 import shutil |
27 import mimetypes | 27 import mimetypes |
28 from jnius import autoclass, cast | 28 from jnius import autoclass, cast |
29 from android import activity | 29 from android import activity |
30 from android.permissions import request_permissions, Permission | |
31 from kivy.clock import Clock | |
32 from kivy.uix.label import Label | |
30 from sat.core.i18n import _ | 33 from sat.core.i18n import _ |
31 from sat.core import log as logging | 34 from sat.core import log as logging |
32 from sat_frontends.tools import jid | 35 from sat_frontends.tools import jid |
33 from cagou.core.constants import Const as C | 36 from cagou.core.constants import Const as C |
34 from cagou.core import dialog | 37 from cagou.core import dialog |
35 from cagou import G | 38 from cagou import G |
36 from kivy.clock import Clock | |
37 from .base import Platform as BasePlatform | 39 from .base import Platform as BasePlatform |
38 | 40 |
39 | 41 |
40 log = logging.getLogger(__name__) | 42 log = logging.getLogger(__name__) |
43 | |
44 # permission that are necessary to have Cagou running properly | |
45 PERMISSION_MANDATORY = [ | |
46 Permission.READ_EXTERNAL_STORAGE, | |
47 Permission.WRITE_EXTERNAL_STORAGE, | |
48 ] | |
41 | 49 |
42 service = autoclass('org.salutatoi.cagou.ServiceBackend') | 50 service = autoclass('org.salutatoi.cagou.ServiceBackend') |
43 PythonActivity = autoclass('org.kivy.android.PythonActivity') | 51 PythonActivity = autoclass('org.kivy.android.PythonActivity') |
44 mActivity = PythonActivity.mActivity | 52 mActivity = PythonActivity.mActivity |
45 Intent = autoclass('android.content.Intent') | 53 Intent = autoclass('android.content.Intent') |
107 | 115 |
108 def profileAutoconnectGetEb(self, failure_): | 116 def profileAutoconnectGetEb(self, failure_): |
109 log.error(f"Error while getting profile to autoconnect: {failure_}") | 117 log.error(f"Error while getting profile to autoconnect: {failure_}") |
110 G.host.postInit() | 118 G.host.postInit() |
111 | 119 |
120 def _show_perm_warning(self, permissions): | |
121 root_wid = G.host.app.root | |
122 perm_warning = Label( | |
123 size_hint=(1, 1), | |
124 text_size=(root_wid.width, root_wid.height), | |
125 font_size='22sp', | |
126 bold=True, | |
127 color=(0.67, 0, 0, 1), | |
128 halign='center', | |
129 valign='center', | |
130 text=_( | |
131 "Requested permissions are mandatory to run Cagou, if you don't " | |
132 "accept them, Cagou can't run properly. Please accept following " | |
133 "permissions, or set them in Android settings for Cagou:\n" | |
134 "{permissions}\n\nCagou will be closed in 20 s").format( | |
135 permissions='\n'.join(p.split('.')[-1] for p in permissions))) | |
136 root_wid.clear_widgets() | |
137 root_wid.add_widget(perm_warning) | |
138 Clock.schedule_once(lambda *args: G.host.app.stop(), 20) | |
139 | |
140 def permission_cb(self, permissions, grant_results): | |
141 if not all(grant_results): | |
142 # we keep asking until they are accepted, as we can't run properly | |
143 # without them | |
144 # TODO: a message explaining why permission is needed should be printed | |
145 # TODO: the storage permission is mainly used to set download_dir, we should | |
146 # be able to run Cagou without it. | |
147 if not hasattr(self, 'perms_counter'): | |
148 self.perms_counter = 0 | |
149 self.perms_counter += 1 | |
150 if self.perms_counter > 5: | |
151 Clock.schedule_once( | |
152 lambda *args: self._show_perm_warning(permissions), | |
153 0) | |
154 return | |
155 | |
156 perm_dict = dict(zip(permissions, grant_results)) | |
157 log.warning( | |
158 f"not all mandatory permissions are granted, requesting again: " | |
159 f"{perm_dict}") | |
160 request_permissions(PERMISSION_MANDATORY, callback=self.permission_cb) | |
161 return | |
162 | |
163 Clock.schedule_once(lambda *args: G.host.bridge.profileAutoconnectGet( | |
164 callback=self.profileAutoconnectGetCb, | |
165 errback=self.profileAutoconnectGetEb), | |
166 0) | |
167 | |
112 def do_postInit(self): | 168 def do_postInit(self): |
113 G.host.bridge.profileAutoconnectGet( | 169 request_permissions(PERMISSION_MANDATORY, callback=self.permission_cb) |
114 callback=self.profileAutoconnectGetCb, | |
115 errback=self.profileAutoconnectGetEb | |
116 ) | |
117 return False | 170 return False |
118 | 171 |
119 def onProfilePlugged(self, profile): | 172 def onProfilePlugged(self, profile): |
120 log.debug("ANDROID profilePlugged") | 173 log.debug("ANDROID profilePlugged") |
121 G.host.bridge.setParam( | 174 G.host.bridge.setParam( |
296 f"uri: {uri}\n" | 349 f"uri: {uri}\n" |
297 f"path: {path}") | 350 f"path: {path}") |
298 | 351 |
299 log.debug(msg) | 352 log.debug(msg) |
300 | 353 |
354 def check_plugin_permissions(self, plug_info, callback, errback): | |
355 perms = plug_info.get("android_permissons") | |
356 if not perms: | |
357 callback() | |
358 perms = [f"android.permission.{p}" if '.' not in p else p for p in perms] | |
359 | |
360 def request_permissions_cb(permissions, granted): | |
361 if all(granted): | |
362 Clock.schedule_once(lambda *args: callback()) | |
363 else: | |
364 Clock.schedule_once(lambda *args: errback()) | |
365 | |
366 request_permissions(perms, callback=request_permissions_cb) | |
367 | |
301 def open_url(self, url, wid=None): | 368 def open_url(self, url, wid=None): |
302 parsed_url = urlparse(url) | 369 parsed_url = urlparse(url) |
303 if parsed_url.scheme == "geo": | 370 if parsed_url.scheme == "geo": |
304 intent = Intent(Intent.ACTION_VIEW) | 371 intent = Intent(Intent.ACTION_VIEW) |
305 intent.setData(Uri.parse(url)) | 372 intent.setData(Uri.parse(url)) |