You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
6.2 KiB
193 lines
6.2 KiB
import sys |
|
|
|
import requests |
|
from kivy import base, utils |
|
from kivy.clock import Clock |
|
from kivy.core.window import Window |
|
from kivy.factory import Factory |
|
from kivy.lang import Builder |
|
from kivy.uix.label import Label |
|
from kivy.utils import platform |
|
|
|
|
|
from electrum.base_crash_reporter import BaseCrashReporter |
|
from electrum.i18n import _ |
|
|
|
|
|
Builder.load_string(''' |
|
<CrashReporter@Popup> |
|
BoxLayout: |
|
orientation: 'vertical' |
|
Label: |
|
id: crash_message |
|
text_size: root.width, None |
|
size: self.texture_size |
|
size_hint: None, None |
|
Label: |
|
id: request_help_message |
|
text_size: root.width*.95, None |
|
size: self.texture_size |
|
size_hint: None, None |
|
BoxLayout: |
|
size_hint: 1, 0.1 |
|
Button: |
|
text: 'Show report contents' |
|
height: '48dp' |
|
size_hint: 1, None |
|
on_press: root.show_contents() |
|
BoxLayout: |
|
size_hint: 1, 0.1 |
|
Label: |
|
id: describe_error_message |
|
text_size: root.width, None |
|
size: self.texture_size |
|
size_hint: None, None |
|
TextInput: |
|
id: user_message |
|
size_hint: 1, 0.3 |
|
BoxLayout: |
|
size_hint: 1, 0.7 |
|
BoxLayout: |
|
size_hint: 1, None |
|
height: '48dp' |
|
orientation: 'horizontal' |
|
Button: |
|
height: '48dp' |
|
text: 'Send' |
|
on_release: root.send_report() |
|
Button: |
|
text: 'Never' |
|
on_release: root.show_never() |
|
Button: |
|
text: 'Not now' |
|
on_release: root.dismiss() |
|
|
|
<CrashReportDetails@Popup> |
|
BoxLayout: |
|
orientation: 'vertical' |
|
ScrollView: |
|
do_scroll_x: False |
|
Label: |
|
id: contents |
|
text_size: root.width*.9, None |
|
size: self.texture_size |
|
size_hint: None, None |
|
Button: |
|
text: 'Close' |
|
height: '48dp' |
|
size_hint: 1, None |
|
on_release: root.dismiss() |
|
''') |
|
|
|
|
|
class CrashReporter(BaseCrashReporter, Factory.Popup): |
|
issue_template = """[b]Traceback[/b] |
|
|
|
[i]{traceback}[/i] |
|
|
|
|
|
[b]Additional information[/b] |
|
* Electrum version: {app_version} |
|
* Operating system: {os} |
|
* Wallet type: {wallet_type} |
|
* Locale: {locale} |
|
""" |
|
|
|
def __init__(self, main_window, exctype, value, tb): |
|
BaseCrashReporter.__init__(self, exctype, value, tb) |
|
Factory.Popup.__init__(self) |
|
self.main_window = main_window |
|
self.title = BaseCrashReporter.CRASH_TITLE |
|
self.title_size = "24sp" |
|
self.ids.crash_message.text = BaseCrashReporter.CRASH_MESSAGE |
|
self.ids.request_help_message.text = BaseCrashReporter.REQUEST_HELP_MESSAGE |
|
self.ids.describe_error_message.text = BaseCrashReporter.DESCRIBE_ERROR_MESSAGE |
|
|
|
def show_contents(self): |
|
details = CrashReportDetails(self.get_report_string()) |
|
details.open() |
|
|
|
def show_popup(self, title, content): |
|
popup = Factory.Popup(title=title, |
|
content=Label(text=content, text_size=(Window.size[0] * 3/4, None)), |
|
size_hint=(3/4, 3/4)) |
|
popup.open() |
|
|
|
def send_report(self): |
|
try: |
|
response = BaseCrashReporter.send_report(self, "/crash.json").json() |
|
except requests.exceptions.RequestException: |
|
self.show_popup(_('Unable to send report'), _("Please check your network connection.")) |
|
else: |
|
self.show_popup(_('Report sent'), response["text"]) |
|
if response["location"]: |
|
self.open_url(response["location"]) |
|
self.dismiss() |
|
|
|
def open_url(self, url): |
|
if platform != 'android': |
|
return |
|
from jnius import autoclass, cast |
|
String = autoclass("java.lang.String") |
|
url = String(url) |
|
PythonActivity = autoclass('org.kivy.android.PythonActivity') |
|
activity = PythonActivity.mActivity |
|
Intent = autoclass('android.content.Intent') |
|
Uri = autoclass('android.net.Uri') |
|
browserIntent = Intent() |
|
# This line crashes the app: |
|
# browserIntent.setAction(Intent.ACTION_VIEW) |
|
# Luckily we don't need it because the OS is smart enough to recognize the URL |
|
browserIntent.setData(Uri.parse(url)) |
|
currentActivity = cast('android.app.Activity', activity) |
|
currentActivity.startActivity(browserIntent) |
|
|
|
def show_never(self): |
|
self.main_window.electrum_config.set_key(BaseCrashReporter.config_key, False) |
|
self.dismiss() |
|
|
|
def get_user_description(self): |
|
return self.ids.user_message.text |
|
|
|
def get_wallet_type(self): |
|
return self.main_window.wallet.wallet_type |
|
|
|
def get_os_version(self): |
|
if utils.platform is not "android": |
|
return utils.platform |
|
import jnius |
|
bv = jnius.autoclass('android.os.Build$VERSION') |
|
b = jnius.autoclass('android.os.Build') |
|
return "Android {} on {} {} ({})".format(bv.RELEASE, b.BRAND, b.DEVICE, b.DISPLAY) |
|
|
|
|
|
class CrashReportDetails(Factory.Popup): |
|
def __init__(self, text): |
|
Factory.Popup.__init__(self) |
|
self.title = "Report Details" |
|
self.ids.contents.text = text |
|
print(text) |
|
|
|
|
|
class ExceptionHook(base.ExceptionHandler): |
|
def __init__(self, main_window): |
|
super().__init__() |
|
self.main_window = main_window |
|
if not main_window.electrum_config.get(BaseCrashReporter.config_key, default=True): |
|
return |
|
# For exceptions in Kivy: |
|
base.ExceptionManager.add_handler(self) |
|
# For everything else: |
|
sys.excepthook = lambda exctype, value, tb: self.handle_exception(value) |
|
|
|
def handle_exception(self, _inst): |
|
exc_info = sys.exc_info() |
|
# Check if this is an exception from within the exception handler: |
|
import traceback |
|
for item in traceback.extract_tb(exc_info[2]): |
|
if item.filename.endswith("crash_reporter.py"): |
|
return |
|
e = CrashReporter(self.main_window, *exc_info) |
|
# Open in main thread: |
|
Clock.schedule_once(lambda _: e.open(), 0) |
|
return base.ExceptionManager.PASS
|
|
|