Browse Source

qml: don't unbind/unregister the ActivityResultListener from within the ActivityResultListener handler func.

instead, schedule a queued finished signal to unregister the listener after the handler has finished.
See PythonActivity.java in P4A for why this probably causes the most often occurring crash we see on the Play Store:

```
Exception java.lang.RuntimeException:
  at android.app.ActivityThread.deliverResults (ActivityThread.java:5164)
  at android.app.ActivityThread.handleSendResult (ActivityThread.java:5205)
  at android.app.servertransaction.ActivityResultItem.execute (ActivityResultItem.java:51)
  at android.app.servertransaction.TransactionExecutor.executeCallbacks (TransactionExecutor.java:135)
  at android.app.servertransaction.TransactionExecutor.execute (TransactionExecutor.java:95)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2136)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loop (Looper.java:236)
  at android.app.ActivityThread.main (ActivityThread.java:8061)
  at java.lang.reflect.Method.invoke
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:656)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:967)
Caused by java.util.ConcurrentModificationException:
  at java.util.ArrayList$Itr.next (ArrayList.java:860)
  at org.kivy.android.PythonActivity.onActivityResult (PythonActivity.java:218)
  at android.app.Activity.dispatchActivityResult (Activity.java:8501)
  at android.app.ActivityThread.deliverResults (ActivityThread.java:5157)
```
master
Sander van Grieken 2 years ago
parent
commit
450b9a03ce
No known key found for this signature in database
GPG Key ID: 9BCF8209EA402EBA
  1. 2
      electrum/gui/qml/components/main.qml
  2. 48
      electrum/gui/qml/qeqrscanner.py

2
electrum/gui/qml/components/main.qml

@ -413,7 +413,7 @@ ApplicationWindow
Component { Component {
id: _scanDialog id: _scanDialog
QRScanner { QRScanner {
//onClosed: destroy() onFinished: destroy()
} }
} }
Component { Component {

48
electrum/gui/qml/qeqrscanner.py

@ -1,6 +1,6 @@
import os import os
from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, Qt
from PyQt6.QtGui import QGuiApplication from PyQt6.QtGui import QGuiApplication
from electrum.util import send_exception_to_crash_reporter, UserFacingException from electrum.util import send_exception_to_crash_reporter, UserFacingException
@ -10,7 +10,7 @@ from electrum.i18n import _
if 'ANDROID_DATA' in os.environ: if 'ANDROID_DATA' in os.environ:
from jnius import autoclass, cast from jnius import autoclass
from android import activity from android import activity
jpythonActivity = autoclass('org.kivy.android.PythonActivity').mActivity jpythonActivity = autoclass('org.kivy.android.PythonActivity').mActivity
@ -23,10 +23,18 @@ class QEQRScanner(QObject):
found = pyqtSignal() found = pyqtSignal()
finished = pyqtSignal()
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
self._hint = _("Scan a QR code.") self._hint = _("Scan a QR code.")
self._scan_data = "" # decoded qr code result self._scan_data = "" # decoded qr code result
self.finished.connect(self._unbind, Qt.ConnectionType.QueuedConnection)
self.destroyed.connect(lambda: self.on_destroy())
def on_destroy(self):
self._unbind()
@pyqtProperty(str) @pyqtProperty(str)
def hint(self): def hint(self):
@ -49,34 +57,34 @@ class QEQRScanner(QObject):
if 'ANDROID_DATA' not in os.environ: if 'ANDROID_DATA' not in os.environ:
self._scan_qr_non_android() self._scan_qr_non_android()
return return
SimpleScannerActivity = autoclass("org.electrum.qr.SimpleScannerActivity") jSimpleScannerActivity = autoclass("org.electrum.qr.SimpleScannerActivity")
intent = jIntent(jpythonActivity, SimpleScannerActivity) intent = jIntent(jpythonActivity, jSimpleScannerActivity)
intent.putExtra(jIntent.EXTRA_TEXT, jString(self._hint)) intent.putExtra(jIntent.EXTRA_TEXT, jString(self._hint))
def on_qr_result(requestCode, resultCode, intent): activity.bind(on_activity_result=self.on_qr_activity_result)
try:
if resultCode == -1: # RESULT_OK:
# this doesn't work due to some bug in jnius:
# contents = intent.getStringExtra("text")
contents = intent.getStringExtra(jString("text"))
#self._logger.info(f"on_qr_result. {contents=!r}")
self.scanData = contents
self.found.emit()
except Exception as e: # exc would otherwise get lost
send_exception_to_crash_reporter(e)
finally:
activity.unbind(on_activity_result=on_qr_result)
activity.bind(on_activity_result=on_qr_result)
jpythonActivity.startActivityForResult(intent, 0) jpythonActivity.startActivityForResult(intent, 0)
def on_qr_activity_result(self, requestCode, resultCode, intent):
try:
if resultCode == -1: # RESULT_OK:
contents = intent.getStringExtra(jString("text"))
self.scanData = contents
self.found.emit()
except Exception as e: # exc would otherwise get lost
send_exception_to_crash_reporter(e)
finally:
self.finished.emit()
@pyqtSlot() @pyqtSlot()
def close(self): def _unbind(self):
pass if 'ANDROID_DATA' in os.environ:
activity.unbind(on_activity_result=self.on_qr_activity_result)
def _scan_qr_non_android(self): def _scan_qr_non_android(self):
data = QGuiApplication.clipboard().text() data = QGuiApplication.clipboard().text()
self.scanData = data self.scanData = data
self.found.emit() self.found.emit()
self.finished.emit()
return return
# from electrum import qrscanner # from electrum import qrscanner
# from .qeapp import ElectrumQmlApplication # from .qeapp import ElectrumQmlApplication

Loading…
Cancel
Save