Mercurial > libervia-backend
comparison sat/plugins/plugin_misc_android.py @ 4037:524856bd7b19
massive refactoring to switch from camelCase to snake_case:
historically, Libervia (SàT before) was using camelCase as allowed by PEP8 when using a
pre-PEP8 code, to use the same coding style as in Twisted.
However, snake_case is more readable and it's better to follow PEP8 best practices, so it
has been decided to move on full snake_case. Because Libervia has a huge codebase, this
ended with a ugly mix of camelCase and snake_case.
To fix that, this patch does a big refactoring by renaming every function and method
(including bridge) that are not coming from Twisted or Wokkel, to use fully snake_case.
This is a massive change, and may result in some bugs.
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 08 Apr 2023 13:54:42 +0200 |
parents | 3910ad643e9d |
children | c23cad65ae99 |
comparison
equal
deleted
inserted
replaced
4036:c4464d7ae97b | 4037:524856bd7b19 |
---|---|
141 app_context = activity.getApplication().getApplicationContext() | 141 app_context = activity.getApplication().getApplicationContext() |
142 notification_intent = Intent(app_context, python_act) | 142 notification_intent = Intent(app_context, python_act) |
143 | 143 |
144 notification_intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) | 144 notification_intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) |
145 notification_intent.setAction(Intent.ACTION_MAIN) | 145 notification_intent.setAction(Intent.ACTION_MAIN) |
146 notification_intent.addCategory(Intent.CATEGORY_LAUNCHER) | 146 notification_intent.add_category(Intent.CATEGORY_LAUNCHER) |
147 if sat_action is not None: | 147 if sat_action is not None: |
148 action_data = AndroidString(json.dumps(sat_action).encode()) | 148 action_data = AndroidString(json.dumps(sat_action).encode()) |
149 log.debug(f"adding extra {INTENT_EXTRA_ACTION} ==> {action_data}") | 149 log.debug(f"adding extra {INTENT_EXTRA_ACTION} ==> {action_data}") |
150 notification_intent = notification_intent.putExtra( | 150 notification_intent = notification_intent.putExtra( |
151 INTENT_EXTRA_ACTION, action_data) | 151 INTENT_EXTRA_ACTION, action_data) |
231 """.format( | 231 """.format( |
232 category_name=PARAM_VIBRATE_CATEGORY, | 232 category_name=PARAM_VIBRATE_CATEGORY, |
233 category_label=D_(PARAM_VIBRATE_CATEGORY), | 233 category_label=D_(PARAM_VIBRATE_CATEGORY), |
234 vibrate_param_name=PARAM_VIBRATE_NAME, | 234 vibrate_param_name=PARAM_VIBRATE_NAME, |
235 vibrate_param_label=PARAM_VIBRATE_LABEL, | 235 vibrate_param_label=PARAM_VIBRATE_LABEL, |
236 vibrate_options=params.makeOptions(VIBRATION_OPTS, "always"), | 236 vibrate_options=params.make_options(VIBRATION_OPTS, "always"), |
237 ring_param_name=PARAM_RING_NAME, | 237 ring_param_name=PARAM_RING_NAME, |
238 ring_param_label=PARAM_RING_LABEL, | 238 ring_param_label=PARAM_RING_LABEL, |
239 ring_options=params.makeOptions(RING_OPTS, "normal"), | 239 ring_options=params.make_options(RING_OPTS, "normal"), |
240 ) | 240 ) |
241 | 241 |
242 def __init__(self, host): | 242 def __init__(self, host): |
243 log.info(_("plugin Android initialization")) | 243 log.info(_("plugin Android initialization")) |
244 log.info(f"using Android API {api_version}") | 244 log.info(f"using Android API {api_version}") |
245 self.host = host | 245 self.host = host |
246 self._csi = host.plugins.get('XEP-0352') | 246 self._csi = host.plugins.get('XEP-0352') |
247 self._csi_timer = None | 247 self._csi_timer = None |
248 host.memory.updateParams(self.params) | 248 host.memory.update_params(self.params) |
249 try: | 249 try: |
250 os.mkdir(SOCKET_DIR, 0o700) | 250 os.mkdir(SOCKET_DIR, 0o700) |
251 except OSError as e: | 251 except OSError as e: |
252 if e.errno == 17: | 252 if e.errno == 17: |
253 # dir already exists | 253 # dir already exists |
266 reactor.listenUNIX(socket_path, factory) | 266 reactor.listenUNIX(socket_path, factory) |
267 else: | 267 else: |
268 raise e | 268 raise e |
269 # we set a low priority because we want the notification to be sent after all | 269 # we set a low priority because we want the notification to be sent after all |
270 # plugins have done their job | 270 # plugins have done their job |
271 host.trigger.add("messageReceived", self.messageReceivedTrigger, priority=-1000) | 271 host.trigger.add("messageReceived", self.message_received_trigger, priority=-1000) |
272 | 272 |
273 # profiles autoconnection | 273 # profiles autoconnection |
274 host.bridge.addMethod( | 274 host.bridge.add_method( |
275 "profileAutoconnectGet", | 275 "profile_autoconnect_get", |
276 ".plugin", | 276 ".plugin", |
277 in_sign="", | 277 in_sign="", |
278 out_sign="s", | 278 out_sign="s", |
279 method=self._profileAutoconnectGet, | 279 method=self._profile_autoconnect_get, |
280 async_=True, | 280 async_=True, |
281 ) | 281 ) |
282 | 282 |
283 # audio manager, to get ring status | 283 # audio manager, to get ring status |
284 self.am = activity.getSystemService(Context.AUDIO_SERVICE) | 284 self.am = activity.getSystemService(Context.AUDIO_SERVICE) |
285 | 285 |
286 # sound notification | 286 # sound notification |
287 media_dir = Path(host.memory.getConfig("", "media_dir")) | 287 media_dir = Path(host.memory.config_get("", "media_dir")) |
288 assert media_dir is not None | 288 assert media_dir is not None |
289 notif_path = media_dir / "sounds" / "notifications" / "music-box.mp3" | 289 notif_path = media_dir / "sounds" / "notifications" / "music-box.mp3" |
290 self.notif_player = MediaPlayer() | 290 self.notif_player = MediaPlayer() |
291 self.notif_player.setDataSource(str(notif_path)) | 291 self.notif_player.setDataSource(str(notif_path)) |
292 self.notif_player.setAudioStreamType(AudioManager.STREAM_NOTIFICATION) | 292 self.notif_player.setAudioStreamType(AudioManager.STREAM_NOTIFICATION) |
295 # SSL fix | 295 # SSL fix |
296 _sslverify.platformTrust = platformTrust | 296 _sslverify.platformTrust = platformTrust |
297 log.info("SSL Android patch applied") | 297 log.info("SSL Android patch applied") |
298 | 298 |
299 # DNS fix | 299 # DNS fix |
300 defer.ensureDeferred(self.updateResolver()) | 300 defer.ensureDeferred(self.update_resolver()) |
301 | 301 |
302 # Connectivity handling | 302 # Connectivity handling |
303 self.cm = activity.getSystemService(Context.CONNECTIVITY_SERVICE) | 303 self.cm = activity.getSystemService(Context.CONNECTIVITY_SERVICE) |
304 self._net_type = None | 304 self._net_type = None |
305 d = defer.ensureDeferred(self._checkConnectivity()) | 305 d = defer.ensureDeferred(self._check_connectivity()) |
306 d.addErrback(host.logErrback) | 306 d.addErrback(host.log_errback) |
307 | 307 |
308 # XXX: we need to keep a reference to BroadcastReceiver to avoid | 308 # XXX: we need to keep a reference to BroadcastReceiver to avoid |
309 # "XXX has no attribute 'invoke'" error (looks like the same issue as | 309 # "XXX has no attribute 'invoke'" error (looks like the same issue as |
310 # https://github.com/kivy/pyjnius/issues/59) | 310 # https://github.com/kivy/pyjnius/issues/59) |
311 self.br = BroadcastReceiver( | 311 self.br = BroadcastReceiver( |
312 callback=lambda *args, **kwargs: reactor.callFromThread( | 312 callback=lambda *args, **kwargs: reactor.callFromThread( |
313 self.onConnectivityChange | 313 self.on_connectivity_change |
314 ), | 314 ), |
315 actions=["android.net.conn.CONNECTIVITY_CHANGE"] | 315 actions=["android.net.conn.CONNECTIVITY_CHANGE"] |
316 ) | 316 ) |
317 self.br.start() | 317 self.br.start() |
318 | 318 |
324 def state(self, new_state): | 324 def state(self, new_state): |
325 log.debug(f"frontend state has changed: {new_state.decode()}") | 325 log.debug(f"frontend state has changed: {new_state.decode()}") |
326 previous_state = self._state | 326 previous_state = self._state |
327 self._state = new_state | 327 self._state = new_state |
328 if new_state == STATE_RUNNING: | 328 if new_state == STATE_RUNNING: |
329 self._onRunning(previous_state) | 329 self._on_running(previous_state) |
330 elif new_state == STATE_PAUSED: | 330 elif new_state == STATE_PAUSED: |
331 self._onPaused(previous_state) | 331 self._on_paused(previous_state) |
332 elif new_state == STATE_STOPPED: | 332 elif new_state == STATE_STOPPED: |
333 self._onStopped(previous_state) | 333 self._on_stopped(previous_state) |
334 | 334 |
335 @property | 335 @property |
336 def cagou_active(self): | 336 def cagou_active(self): |
337 return self._state == STATE_RUNNING | 337 return self._state == STATE_RUNNING |
338 | 338 |
339 def _onRunning(self, previous_state): | 339 def _on_running(self, previous_state): |
340 if previous_state is not None: | 340 if previous_state is not None: |
341 self.host.bridge.bridgeReactivateSignals() | 341 self.host.bridge.bridge_reactivate_signals() |
342 self.setActive() | 342 self.set_active() |
343 | 343 |
344 def _onPaused(self, previous_state): | 344 def _on_paused(self, previous_state): |
345 self.host.bridge.bridgeDeactivateSignals() | 345 self.host.bridge.bridge_deactivate_signals() |
346 self.setInactive() | 346 self.set_inactive() |
347 | 347 |
348 def _onStopped(self, previous_state): | 348 def _on_stopped(self, previous_state): |
349 self.setInactive() | 349 self.set_inactive() |
350 | 350 |
351 def _notifyMessage(self, mess_data, client): | 351 def _notify_message(self, mess_data, client): |
352 """Send notification when suitable | 352 """Send notification when suitable |
353 | 353 |
354 notification is sent if: | 354 notification is sent if: |
355 - there is a message and it is not a groupchat | 355 - there is a message and it is not a groupchat |
356 - message is not coming from ourself | 356 - message is not coming from ourself |
376 ) | 376 ) |
377 | 377 |
378 ringer_mode = self.am.getRingerMode() | 378 ringer_mode = self.am.getRingerMode() |
379 vibrate_mode = ringer_mode == AudioManager.RINGER_MODE_VIBRATE | 379 vibrate_mode = ringer_mode == AudioManager.RINGER_MODE_VIBRATE |
380 | 380 |
381 ring_setting = self.host.memory.getParamA( | 381 ring_setting = self.host.memory.param_get_a( |
382 PARAM_RING_NAME, | 382 PARAM_RING_NAME, |
383 PARAM_RING_CATEGORY, | 383 PARAM_RING_CATEGORY, |
384 profile_key=client.profile | 384 profile_key=client.profile |
385 ) | 385 ) |
386 | 386 |
387 if ring_setting != 'never' and ringer_mode == AudioManager.RINGER_MODE_NORMAL: | 387 if ring_setting != 'never' and ringer_mode == AudioManager.RINGER_MODE_NORMAL: |
388 self.notif_player.start() | 388 self.notif_player.start() |
389 | 389 |
390 vibration_setting = self.host.memory.getParamA( | 390 vibration_setting = self.host.memory.param_get_a( |
391 PARAM_VIBRATE_NAME, | 391 PARAM_VIBRATE_NAME, |
392 PARAM_VIBRATE_CATEGORY, | 392 PARAM_VIBRATE_CATEGORY, |
393 profile_key=client.profile | 393 profile_key=client.profile |
394 ) | 394 ) |
395 if (vibration_setting == 'always' | 395 if (vibration_setting == 'always' |
398 vibrator.vibrate() | 398 vibrator.vibrate() |
399 except Exception as e: | 399 except Exception as e: |
400 log.warning("Can't use vibrator: {e}".format(e=e)) | 400 log.warning("Can't use vibrator: {e}".format(e=e)) |
401 return mess_data | 401 return mess_data |
402 | 402 |
403 def messageReceivedTrigger(self, client, message_elt, post_treat): | 403 def message_received_trigger(self, client, message_elt, post_treat): |
404 if not self.cagou_active: | 404 if not self.cagou_active: |
405 # we only send notification is the frontend is not displayed | 405 # we only send notification is the frontend is not displayed |
406 post_treat.addCallback(self._notifyMessage, client) | 406 post_treat.addCallback(self._notify_message, client) |
407 | 407 |
408 return True | 408 return True |
409 | 409 |
410 # Profile autoconnection | 410 # Profile autoconnection |
411 | 411 |
412 def _profileAutoconnectGet(self): | 412 def _profile_autoconnect_get(self): |
413 return defer.ensureDeferred(self.profileAutoconnectGet()) | 413 return defer.ensureDeferred(self.profile_autoconnect_get()) |
414 | 414 |
415 async def _getProfilesAutoconnect(self): | 415 async def _get_profiles_autoconnect(self): |
416 autoconnect_dict = await self.host.memory.storage.getIndParamValues( | 416 autoconnect_dict = await self.host.memory.storage.get_ind_param_values( |
417 category='Connection', name='autoconnect_backend', | 417 category='Connection', name='autoconnect_backend', |
418 ) | 418 ) |
419 return [p for p, v in autoconnect_dict.items() if C.bool(v)] | 419 return [p for p, v in autoconnect_dict.items() if C.bool(v)] |
420 | 420 |
421 async def profileAutoconnectGet(self): | 421 async def profile_autoconnect_get(self): |
422 """Return profile to connect automatically by frontend, if any""" | 422 """Return profile to connect automatically by frontend, if any""" |
423 profiles_autoconnect = await self._getProfilesAutoconnect() | 423 profiles_autoconnect = await self._get_profiles_autoconnect() |
424 if not profiles_autoconnect: | 424 if not profiles_autoconnect: |
425 return None | 425 return None |
426 if len(profiles_autoconnect) > 1: | 426 if len(profiles_autoconnect) > 1: |
427 log.warning( | 427 log.warning( |
428 f"More that one profiles with backend autoconnection set found, picking " | 428 f"More that one profiles with backend autoconnection set found, picking " |
429 f"up first one (full list: {profiles_autoconnect!r})") | 429 f"up first one (full list: {profiles_autoconnect!r})") |
430 return profiles_autoconnect[0] | 430 return profiles_autoconnect[0] |
431 | 431 |
432 # CSI | 432 # CSI |
433 | 433 |
434 def _setInactive(self): | 434 def _set_inactive(self): |
435 self._csi_timer = None | 435 self._csi_timer = None |
436 for client in self.host.getClients(C.PROF_KEY_ALL): | 436 for client in self.host.get_clients(C.PROF_KEY_ALL): |
437 self._csi.setInactive(client) | 437 self._csi.set_inactive(client) |
438 | 438 |
439 def setInactive(self): | 439 def set_inactive(self): |
440 if self._csi is None or self._csi_timer is not None: | 440 if self._csi is None or self._csi_timer is not None: |
441 return | 441 return |
442 self._csi_timer = reactor.callLater(CSI_DELAY, self._setInactive) | 442 self._csi_timer = reactor.callLater(CSI_DELAY, self._set_inactive) |
443 | 443 |
444 def setActive(self): | 444 def set_active(self): |
445 if self._csi is None: | 445 if self._csi is None: |
446 return | 446 return |
447 if self._csi_timer is not None: | 447 if self._csi_timer is not None: |
448 self._csi_timer.cancel() | 448 self._csi_timer.cancel() |
449 self._csi_timer = None | 449 self._csi_timer = None |
450 for client in self.host.getClients(C.PROF_KEY_ALL): | 450 for client in self.host.get_clients(C.PROF_KEY_ALL): |
451 self._csi.setActive(client) | 451 self._csi.set_active(client) |
452 | 452 |
453 # Connectivity | 453 # Connectivity |
454 | 454 |
455 async def _handleNetworkChange(self, net_type): | 455 async def _handle_network_change(self, net_type): |
456 """Notify the clients about network changes. | 456 """Notify the clients about network changes. |
457 | 457 |
458 This way the client can disconnect/reconnect transport, or change delays | 458 This way the client can disconnect/reconnect transport, or change delays |
459 """ | 459 """ |
460 log.debug(f"handling network change ({net_type})") | 460 log.debug(f"handling network change ({net_type})") |
461 if net_type == NET_TYPE_NONE: | 461 if net_type == NET_TYPE_NONE: |
462 for client in self.host.getClients(C.PROF_KEY_ALL): | 462 for client in self.host.get_clients(C.PROF_KEY_ALL): |
463 client.networkDisabled() | 463 client.network_disabled() |
464 else: | 464 else: |
465 # DNS servers may have changed | 465 # DNS servers may have changed |
466 await self.updateResolver() | 466 await self.update_resolver() |
467 # client may be there but disabled (e.g. with stream management) | 467 # client may be there but disabled (e.g. with stream management) |
468 for client in self.host.getClients(C.PROF_KEY_ALL): | 468 for client in self.host.get_clients(C.PROF_KEY_ALL): |
469 log.debug(f"enabling network for {client.profile}") | 469 log.debug(f"enabling network for {client.profile}") |
470 client.networkEnabled() | 470 client.network_enabled() |
471 | 471 |
472 # profiles may have been disconnected and then purged, we try | 472 # profiles may have been disconnected and then purged, we try |
473 # to reconnect them in case | 473 # to reconnect them in case |
474 profiles_autoconnect = await self._getProfilesAutoconnect() | 474 profiles_autoconnect = await self._get_profiles_autoconnect() |
475 for profile in profiles_autoconnect: | 475 for profile in profiles_autoconnect: |
476 if not self.host.isConnected(profile): | 476 if not self.host.is_connected(profile): |
477 log.info(f"{profile} is not connected, reconnecting it") | 477 log.info(f"{profile} is not connected, reconnecting it") |
478 try: | 478 try: |
479 await self.host.connect(profile) | 479 await self.host.connect(profile) |
480 except Exception as e: | 480 except Exception as e: |
481 log.error(f"Can't connect profile {profile}: {e}") | 481 log.error(f"Can't connect profile {profile}: {e}") |
482 | 482 |
483 async def _checkConnectivity(self): | 483 async def _check_connectivity(self): |
484 active_network = self.cm.getActiveNetworkInfo() | 484 active_network = self.cm.getActiveNetworkInfo() |
485 if active_network is None: | 485 if active_network is None: |
486 net_type = NET_TYPE_NONE | 486 net_type = NET_TYPE_NONE |
487 else: | 487 else: |
488 net_type_android = active_network.getType() | 488 net_type_android = active_network.getType() |
504 log.info("mobile data activated") | 504 log.info("mobile data activated") |
505 else: | 505 else: |
506 log.info("network activated (type={net_type_android})" | 506 log.info("network activated (type={net_type_android})" |
507 .format(net_type_android=net_type_android)) | 507 .format(net_type_android=net_type_android)) |
508 else: | 508 else: |
509 log.debug("_checkConnectivity called without network change ({net_type})" | 509 log.debug("_check_connectivity called without network change ({net_type})" |
510 .format(net_type = net_type)) | 510 .format(net_type = net_type)) |
511 | 511 |
512 # we always call _handleNetworkChange even if there is not connectivity change | 512 # we always call _handle_network_change even if there is not connectivity change |
513 # to be sure to reconnect when necessary | 513 # to be sure to reconnect when necessary |
514 await self._handleNetworkChange(net_type) | 514 await self._handle_network_change(net_type) |
515 | 515 |
516 | 516 |
517 def onConnectivityChange(self): | 517 def on_connectivity_change(self): |
518 log.debug("onConnectivityChange called") | 518 log.debug("on_connectivity_change called") |
519 d = defer.ensureDeferred(self._checkConnectivity()) | 519 d = defer.ensureDeferred(self._check_connectivity()) |
520 d.addErrback(self.host.logErrback) | 520 d.addErrback(self.host.log_errback) |
521 | 521 |
522 async def updateResolver(self): | 522 async def update_resolver(self): |
523 # There is no "/etc/resolv.conf" on Android, which confuse Twisted and makes | 523 # There is no "/etc/resolv.conf" on Android, which confuse Twisted and makes |
524 # SRV record checking unusable. We fixe that by checking DNS server used, and | 524 # SRV record checking unusable. We fixe that by checking DNS server used, and |
525 # updating Twisted's resolver accordingly | 525 # updating Twisted's resolver accordingly |
526 dns_servers = await self.getDNSServers() | 526 dns_servers = await self.get_dns_servers() |
527 | 527 |
528 log.info( | 528 log.info( |
529 "Patching Twisted to use Android DNS resolver ({dns_servers})".format( | 529 "Patching Twisted to use Android DNS resolver ({dns_servers})".format( |
530 dns_servers=', '.join([s[0] for s in dns_servers])) | 530 dns_servers=', '.join([s[0] for s in dns_servers])) |
531 ) | 531 ) |
532 dns_client.theResolver = dns_client.createResolver(servers=dns_servers) | 532 dns_client.theResolver = dns_client.createResolver(servers=dns_servers) |
533 | 533 |
534 async def getDNSServers(self): | 534 async def get_dns_servers(self): |
535 servers = [] | 535 servers = [] |
536 | 536 |
537 if api_version < 26: | 537 if api_version < 26: |
538 # thanks to A-IV at https://stackoverflow.com/a/11362271 for the way to go | 538 # thanks to A-IV at https://stackoverflow.com/a/11362271 for the way to go |
539 log.debug("Old API, using SystemProperties to find DNS") | 539 log.debug("Old API, using SystemProperties to find DNS") |