URI: 
       tmanage exchange plugins, make sure ui doesn't stall while saving seed and numerous other small fixes. - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 1179a4cf9e11a41ada5f8dfc006a92c71da3aa8d
   DIR parent 1bbb211671e46702ec913f5bddffbb0665ff6bbc
  HTML Author: qua-non <akshayaurora@gmail.com>
       Date:   Tue, 11 Mar 2014 00:18:12 +0530
       
       manage exchange plugins, make sure ui doesn't stall while saving seed
       and numerous other small fixes.
       
       Diffstat:
         M gui/kivy/dialog.py                  |       4 +++-
         M gui/kivy/drawer.py                  |      15 +++++++++++----
         M gui/kivy/installwizard.py           |      28 +++++++++++++++++-----------
         M gui/kivy/main.kv                    |       3 ++-
         M gui/kivy/main_window.py             |      53 +++++++++++++++++++------------
         M gui/kivy/plugins/exchange_rate.py   |     325 +++++++++++++++++++++++--------
         M lib/util.py                         |       7 +++++++
       
       7 files changed, 316 insertions(+), 119 deletions(-)
       ---
   DIR diff --git a/gui/kivy/dialog.py b/gui/kivy/dialog.py
       t@@ -192,7 +192,7 @@ class InfoBubble(Bubble):
                anim.start(self)
        
        
       -    def hide(self, *dt):
       +    def hide(self, now=False):
                ''' Auto fade out the Bubble
                '''
                def on_stop(*l):
       t@@ -205,6 +205,8 @@ class InfoBubble(Bubble):
                        App.get_running_app().stop()
                        import sys
                        sys.exit()
       +        if now:
       +            return on_stop()
        
                anim = Animation(opacity=0, d=.25)
                anim.bind(on_complete=on_stop)
   DIR diff --git a/gui/kivy/drawer.py b/gui/kivy/drawer.py
       t@@ -82,11 +82,13 @@ class Drawer(StencilView):
                if app.ui_mode[0] == 't':
                    return super(Drawer, self).on_touch_down(touch)
        
       +        state = self.state
                touch.ud['send_touch_down'] = False
       +        start = 0 if state[0] == 'c' else self._hidden_widget.right
                drag_area = ((self.width * self.drag_area)
                            if self.state[0] == 'c' else
       -                    self._hidden_widget.width)
       -        if touch.x > drag_area:
       +                    self.width)
       +        if touch.x not in range(int(start), int(drag_area)):
                    return super(Drawer, self).on_touch_down(touch)
                self._touch = touch
                Clock.schedule_once(self._change_touch_mode,
       t@@ -106,8 +108,13 @@ class Drawer(StencilView):
                if not touch.ud.get('in_drag_area', None):
                    return super(Drawer, self).on_touch_move(touch)
        
       -        self._overlay_widget.x = min(self._hidden_widget.width,
       -                        max(self._overlay_widget.x + touch.dx*2, 0))
       +        ov = self._overlay_widget
       +        ov.x=min(self._hidden_widget.width,
       +            max(ov.x + touch.dx*2, 0))
       +        #_anim = Animation(x=x, duration=1/60)
       +        #_anim.cancel_all(ov)
       +        #_anim.start(ov)
       +
                if abs(touch.x - touch.ox) < self.scroll_distance:
                    return
                touch.ud['send_touch_down'] = False
   DIR diff --git a/gui/kivy/installwizard.py b/gui/kivy/installwizard.py
       t@@ -45,10 +45,16 @@ class InstallWizard(Widget):
                '''
        
                def target():
       +
                    # run your threaded function
       -            task()
       +            try:
       +                task()
       +            except Exception as err:
       +                Clock.schedule_once(lambda dt: app.show_error(str(err)))
       +
                    # on  completion hide message
       -            Clock.schedule_once(lambda dt: app.info_bubble.hide())
       +            Clock.schedule_once(lambda dt: app.info_bubble.hide(now=True), -1)
       +
                    # call completion routine
                    if on_complete:
                        Clock.schedule_once(lambda dt: on_complete())
       t@@ -138,14 +144,14 @@ class InstallWizard(Widget):
        
                brainwallet = seed
        
       -        msg2 = _("[color=#414141][b]"+\
       +        msg2 = _("[color=#414141]"+\
                        "[b]PLEASE WRITE DOWN YOUR SEED PASS[/b][/color]"+\
                        "[size=9]\n\n[/size]" +\
                        "[color=#929292]If you ever forget your pincode, your seed" +\
                        " phrase will be the [color=#EB984E]"+\
                        "[b]only way to recover[/b][/color] your wallet. Your " +\
                        " [color=#EB984E][b]Bitcoins[/b][/color] will otherwise be" +\
       -                " [color=#EB984E]lost forever![/color]")
       +                " [color=#EB984E][b]lost forever![/b][/color]")
        
                if wallet.imported_keys:
                    msg2 += "[b][color=#ff0000ff]" + _("WARNING") + "[/color]:[/b] " +\
       t@@ -234,13 +240,13 @@ class InstallWizard(Widget):
                        return app.show_error(_('Passwords do not match'), duration=.5)
        
                    if mode == 'restore':
       -                try:
       -                    wallet.save_seed(new_password)
       -                except Exception as err:
       -                    app.show_error(str(err))
       -                    return
       -                _dlg.close()
       -                self.load_network(wallet, mode='restore')
       +                def on_complete(*l):
       +                    _dlg.close()
       +                    self.load_network(wallet, mode='restore')
       +
       +                self.waiting_dialog(lambda: wallet.save_seed(new_password),
       +                                    msg=_("saving seed"),
       +                                    on_complete=on_complete)
                        return
                    if not instance:
                        # create
   DIR diff --git a/gui/kivy/main.kv b/gui/kivy/main.kv
       t@@ -2,6 +2,7 @@
        #:import _ electrum.i18n._
        #:import partial functools.partial
        
       +
        # Custom Global Widgets
        
        <VGridLayout@GridLayout>:
       t@@ -27,7 +28,7 @@
        
        <Label>
            markup: True
       -    font_name: 'data/fonts/Roboto.ttf'
       +    font_name: 'Roboto'
            font_size: '16sp'
        
        <ListItemButton>
   DIR diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py
       t@@ -93,7 +93,7 @@ class ElectrumWindow(App):
                                 'While trying to save value to config')
        
            base_unit = AliasProperty(_get_bu, _set_bu, bind=('decimal_point',))
       -    '''BTC or UBTC or ...
       +    '''BTC or UBTC or mBTC...
        
            :attr:`base_unit` is a `AliasProperty` defaults to the unit set in
            electrum config.
       t@@ -148,13 +148,13 @@ class ElectrumWindow(App):
                self.network = network = kwargs.get('network')
                self.electrum_config = config = kwargs.get('config')
        
       -        # create triggers so as to minimize updation a max of 5 times a sec
       +        # create triggers so as to minimize updation a max of 2 times a sec
                self._trigger_update_status =\
       -            Clock.create_trigger(self.update_status, .2)
       +            Clock.create_trigger(self.update_status, .5)
                self._trigger_update_console =\
       -            Clock.create_trigger(self.update_console, .2)
       +            Clock.create_trigger(self.update_console, .5)
                self._trigger_notify_transactions = \
       -            Clock.create_trigger(self.notify_transactions, .2)
       +            Clock.create_trigger(self.notify_transactions, .5)
        
            def build(self):
                from kivy.lang import Builder
       t@@ -174,6 +174,15 @@ class ElectrumWindow(App):
                Window.bind(size=self.on_size,
                            on_keyboard=self.on_keyboard)
                Window.bind(on_key_down=self.on_key_down)
       +
       +        # register fonts
       +        from kivy.core.text import Label
       +        Label.register('Roboto',
       +                   'data/fonts/Roboto.ttf',
       +                   'data/fonts/Roboto.ttf',
       +                   'data/fonts/Roboto-Bold.ttf',
       +                   'data/fonts/Roboto-Bold.ttf')
       +
                if platform == 'android':
                    #
                    Window.bind(keyboard_height=self.on_keyboard_height)
       t@@ -261,17 +270,20 @@ class ElectrumWindow(App):
        
                self.load_wallet(wallet)
        
       -        # check and remove this load_wallet calls update_wallet no
       -        # need for this here
       -        #Clock.schedule_once(update_wallet)
       -
       +        #TODO: URI handling
                #self.windows.append(w)
                #if url: w.set_url(url)
       -        #w.app = self.app
       -        #w.connect_slots(s)
       -        #w.update_wallet()
        
       -        #self.app.exec_()
       +        # TODO:remove properties are used instead
       +        #Clock.schedule_interval(self.timer_actions, .5)
       +
       +
       +    #TODO: remove not needed properties allow on_property events
       +    #def timer_actions(self):
       +    #    if self.need_update.is_set():
       +    #        self.update_wallet()
       +    #        self.need_update.clear()
       +    #    run_hook('timer_actions')
        
            def init_ui(self):
                ''' Initialize The Ux part of electrum. This function performs the basic
       t@@ -326,12 +338,12 @@ class ElectrumWindow(App):
                    from electrum_gui.kivy.plugins.exchange_rate import Exchanger
                    self.exchanger = Exchanger(self)
                    self.exchanger.start()
       -        quote_currency = self.electrum_config.get("currency", 'EUR')
       +        quote_currency = self.exchanger.currency
                quote_balance = self.exchanger.exchange(btc_balance, quote_currency)
        
       -        if mode == 'symbol':
       -            if quote_currency:
       -                quote_currency = self.exchanger.symbols[quote_currency]
       +        if quote_currency and mode == 'symbol':
       +            quote_currency = self.exchanger.symbols.get(quote_currency,
       +                                                        quote_currency)
        
                if quote_balance is None:
                    quote_text = ""
       t@@ -340,8 +352,9 @@ class ElectrumWindow(App):
                return quote_text
        
            def set_currencies(self, quote_currencies):
       -        self._trigger_update_status
       -        #self.currencies = sorted(quote_currencies.keys())
       +        #TODO remove this and just directly update a observable property
       +        self._trigger_update_status()
       +        self.currencies = sorted(quote_currencies.keys())
        
            def update_console(self, *dt):
                if self.console:
       t@@ -399,7 +412,7 @@ class ElectrumWindow(App):
                        #if quote:
                        #    text += "  (%s)"%quote
        
       -                self.notify(_("Balance: ") + text)
       +                #self.notify(_("Balance: ") + text)
                        #icon = QIcon(":icons/status_connected.png")
                else:
                    text = _("Not connected")
   DIR diff --git a/gui/kivy/plugins/exchange_rate.py b/gui/kivy/plugins/exchange_rate.py
       t@@ -2,109 +2,240 @@
        
        '''Module exchange_rate:
        
       -This module is responsible for getting the conversion rates between different
       -currencies.
       +This module is responsible for getting the conversion rates from different
       +bitcoin exchanges.
        '''
        
        from kivy.network.urlrequest import UrlRequest
       -#kivy.event import EventDispatcher
       +from kivy.event import EventDispatcher
       +from kivy.properties import (OptionProperty, StringProperty, AliasProperty,
       +    ListProperty)
        from kivy.clock import Clock
        import decimal
        import json
        
       -class Exchanger(object):
       -    '''
       +EXCHANGES = ["BitcoinAverage",
       +             "BitcoinVenezuela",
       +             "BitPay",
       +             "Blockchain",
       +             "BTCChina",
       +             "CaVirtEx",
       +             "Coinbase",
       +             "CoinDesk",
       +             "LocalBitcoins",
       +             "Winkdex"]
       +
       +
       +class Exchanger(EventDispatcher):
       +    ''' Provide exchanges rate between crypto and different national
       +    currencies. See Module Documentation for details.
            '''
        
            symbols = {'ALL': 'Lek', 'AED': 'د.إ', 'AFN':'؋', 'ARS': '$', 'AMD': '֏',
                'AWG': 'ƒ', 'ANG': 'ƒ', 'AOA': 'Kz', 'BDT': '৳', 'BHD': 'BD',
       -        'BIF': 'FBu', 'BTC': 'BTC', 'BTN': 'Nu',
       -        'AUD': '$', 'AZN': 'ман', 'BSD': '$', 'BBD': '$', 'BYR': 'p',
       +        'BIF': 'FBu', 'BTC': 'BTC', 'BTN': 'Nu', 'CDF': 'FC', 'CHF': 'CHF',
       +        'CLF': 'UF', 'CLP':'$', 'CVE': '$', 'DJF':'Fdj', 'DZD': 'دج',
       +        'AUD': '$', 'AZN': 'ман', 'BSD': '$', 'BBD': '$', 'BYR': 'p', 'CRC': '₡',
                'BZD': 'BZ$', 'BMD': '$', 'BOB': '$b', 'BAM': 'KM', 'BWP': 'P',
                'BGN': 'лв', 'BRL': 'R$', 'BND': '$', 'KHR': '៛', 'CAD': '$',
       -        'KYD': '$', 'USD': '$', 'CLP': '$', 'CNY': '¥', 'COP': '$', 'CRC': '₡',
       +        'ERN': 'Nfk', 'ETB': 'Br', 'KYD': '$', 'USD': '$', 'CLP': '$',
                'HRK': 'kn', 'CUP':'₱', 'CZK': 'Kč', 'DKK': 'kr', 'DOP': 'RD$',
                'XCD': '$', 'EGP': '£', 'SVC': '$' , 'EEK': 'kr', 'EUR': '€',
                'FKP': '£', 'FJD': '$', 'GHC': '¢', 'GIP': '£', 'GTQ': 'Q', 'GBP': '£',
                'GYD': '$', 'HNL': 'L', 'HKD': '$', 'HUF': 'Ft', 'ISK': 'kr',
       -        'INR': '₹', 'IDR': 'Rp', 'IRR': '﷼', 'IMP': '£', 'ILS': '₪',
       +        'INR': '₹', 'IDR': 'Rp', 'IRR': '﷼', 'IMP': '£', 'ILS': '₪', 'COP': '$',
                'JMD': 'J$', 'JPY': '¥', 'JEP': '£', 'KZT': 'лв', 'KPW': '₩',
       -        'KRW': '₩', 'KGS': 'лв', 'LAK': '₭', 'LVL': 'Ls'}
       +        'KRW': '₩', 'KGS': 'лв', 'LAK': '₭', 'LVL': 'Ls', 'CNY': '¥'}
       +
       +    _use_exchange = OptionProperty('Blockchain', options=EXCHANGES)
       +    '''This is the exchange to be used for getting the currency exchange rates
       +    '''
       +
       +    _currency = StringProperty('EUR')
       +    '''internal use only
       +    '''
       +
       +    def _set_currency(self, value):
       +        exchanger = self.exchanger
       +        if self.use_exchange == 'CoinDesk':
       +            self._update_cd_currency(self.currency)
       +            return
       +        try:
       +            self._currency = value
       +            self.electrum_cinfig.set_key('currency', value, True)
       +        except AttributeError:
       +            self._currency = 'EUR'
       +
       +    def _get_currency(self):
       +        try:
       +            self._currency = self.electrum_config.get('currency', 'EUR')
       +        except AttributeError:
       +            pass
       +        finally:
       +            return self._currency
       +
       +    currency = AliasProperty(_get_currency, _set_currency, bind=('_currency',))
       +
       +    currencies = ListProperty(['EUR', 'GBP', 'USD'])
       +    '''List of currencies supported by the current exchanger plugin.
       +
       +    :attr:`currencies` is a `ListProperty` default to ['Eur', 'GBP'. 'USD'].
       +    '''
       +
       +    def _get_useex(self):
       +        if not self.parent:
       +            return self._use_exchange
       +
       +        self._use_exchange = self.parent.electrum_config.get('use_exchange',
       +                                                             'Blockchain')
       +        return self._use_exchange
       +
       +    def _set_useex(self, value):
       +        if not self.parent:
       +            return self._use_exchange
       +        self.parent.electrum_config.set_key('use_exchange', value, True)
       +        self._use_exchange = value
       +
       +    use_exchange = AliasProperty(_get_useex, _set_useex,
       +                                 bind=('_use_exchange', ))
        
            def __init__(self, parent):
       +        super(Exchanger, self).__init__()
                self.parent = parent
                self.quote_currencies = None
       -        self.exchanges = ('BlockChain', 'Coinbase', 'CoinDesk')
       -        try:
       -            self.use_exchange =  parent.electrum_config.get('use_exchange',
       -                                                            'BlockChain')
       -        except AttributeError:
       -            self.use_exchange = 'BlockChain'
       -        self.currencies = self.symbols.keys()
       +        self.exchanges = EXCHANGES
        
            def exchange(self, btc_amount, quote_currency):
                if self.quote_currencies is None:
                    return None
       +
                quote_currencies = self.quote_currencies.copy()
                if quote_currency not in quote_currencies:
                    return None
       -        if self.use_exchange == "CoinDesk":
       -            try:
       -                connection = httplib.HTTPSConnection('api.coindesk.com')
       -                connection.request("GET", "/v1/bpi/currentprice/" + str(quote_currency) + ".json")
       -            except Exception:
       -                return
       -            resp = connection.getresponse()
       -            if resp.reason == httplib.responses[httplib.NOT_FOUND]:
       -                return
       -            try:
       -                resp_rate = json.loads(resp.read())
       -            except Exception:
       -                return
       -            return btc_amount * decimal.Decimal(str(resp_rate["bpi"][str(quote_currency)]["rate_float"]))
       +
                return btc_amount * decimal.Decimal(quote_currencies[quote_currency])
        
       -    def check_rates(self, dt):
       -        if self.use_exchange == 'BlockChain':
       -            self.check_blockchain()
       -        elif self.use_exchange == 'CoinDesk':
       -            self.check_coindesk()
       -        elif self.use_exchange == 'Coinbase':
       -            self.check_coinbase()
       +    def update_rate(self, dt):
       +        ''' This is called from :method:`start` every X seconds; to update the
       +        rates for currencies for the currently selected exchange.
       +        '''
       +        update_rates = {
       +            "BitcoinAverage": self.update_ba,
       +            "BitcoinVenezuela": self.update_bv,
       +            "BitPay": self.update_bp,
       +            "Blockchain": self.update_bc,
       +            "BTCChina": self.update_CNY,
       +            "CaVirtEx": self.update_cv,
       +            "CoinDesk": self.update_cd,
       +            "Coinbase": self.update_cb,
       +            "LocalBitcoins": self.update_lb,
       +            "Winkdex": self.update_wd,
       +        }
       +        try:
       +            update_rates[self.use_exchange]()
       +        except KeyError:
       +            return
        
       -    def check_coindesk(self):
       +    def update_wd(self):
        
       -        def _lookup_rate(response, quote_id):
       -            return decimal.Decimal(str(response[str(quote_id)]["15m"]))
       +        def on_success(request, response):
       +            response = json.loads(response)
       +            quote_currencies = {'USD': 0.0}
       +            lenprices = len(response["prices"])
       +            usdprice = response['prices'][lenprices-1]['y']
       +
       +            try:
       +                quote_currencies["USD"] = decimal.Decimal(usdprice)
       +            except KeyError:
       +                pass
       +
       +            self.quote_currencies = quote_currencies
       +            self.parent.set_currencies(quote_currencies)
       +
       +        req = UrlRequest(
       +            url='https://winkdex.com/static/data/0_600_288.json',
       +                        on_success=on_success,
       +                        timeout=5)
       +
       +    def update_cd_currency(self, currency):
       +
       +        def on_success(request, response):
       +            response = json.loads(response)
       +            quote_currencies = self.quote_currencies
       +            quote_currencies[currency] =\
       +                str(response['bpi'][str(currency)]['rate_float'])
       +            self.parent.set_currencies(quote_currencies)
       +
       +        req = UrlRequest(
       +            url='https://api.coindesk.com/v1/bpi/currentprice/'\
       +                + str(currency) + '.json',on_success=on_success, timeout=5)
       +
       +    def update_cd(self):
        
                def on_success(request, response):
                    quote_currencies = {}
       +            response = json.loads(response)
       +
       +            for cur in response:
       +                quote_currencies[str(cur["currency"])] = 0.0
       +
       +            self.quote_currencies = quote_currencies
       +            self.update_cd_currency(self.currency)
       +
       +        req = UrlRequest(
       +            url='https://api.coindesk.com/v1/bpi/supported-currencies.json',
       +                        on_success=on_success,
       +                        timeout=5)
       +
       +    def update_cv(self):
       +        def on_success(request, response):
       +            response = json.loads(response)
       +            quote_currencies = {"CAD": 0.0}
       +            cadprice = response["last"]
                    try:
       -                for r in response:
       -                    quote_currencies[r] = _lookup_rate(response, r)
       +                quote_currencies["CAD"] = decimal.Decimal(cadprice)
                        self.quote_currencies = quote_currencies
                    except KeyError:
                        pass
                    self.parent.set_currencies(quote_currencies)
        
       -        def on_failure(*args):
       -            pass
       +        req = UrlRequest(url='https://www.cavirtex.com/api/CAD/ticker.json',
       +                        on_success=on_success,
       +                        timeout=5)
        
       -        def on_error(*args):
       -            pass
       +    def update_CNY(self):
        
       -        def on_redirect(*args):
       -            pass
       +        def on_success(request, response):
       +            quote_currencies = {"CNY": 0.0}
       +            cnyprice = response["ticker"]["last"]
       +            try:
       +                quote_currencies["CNY"] = decimal.Decimal(cnyprice)
       +                self.quote_currencies = quote_currencies
       +            except KeyError:
       +                pass
       +            self.parent.set_currencies(quote_currencies)
        
       -        req = UrlRequest(
       -            url='https://api.coindesk.com/v1/bpi/supported-currencies.json',
       +        req = UrlRequest(url='https://data.btcchina.com/data/ticker',
       +                        on_success=on_success,
       +                        timeout=5)
       +
       +    def update_bp(self):
       +
       +        def on_success(request, response):
       +            quote_currencies = {}
       +            try:
       +                for r in response:
       +                    quote_currencies[str(r['code'])] = decimal.Decimal(r['rate'])
       +                self.quote_currencies = quote_currencies
       +            except KeyError:
       +                pass
       +            self.parent.set_currencies(quote_currencies)
       +
       +        req = UrlRequest(url='https://bitpay.com/api/rates',
                                on_success=on_success,
       -                        on_failure=on_failure,
       -                        on_error=on_error,
       -                        on_redirect=on_redirect,
                                timeout=5)
        
       -    def check_coinbase(self):
       +    def update_cb(self):
        
                def _lookup_rate(response, quote_id):
                    return decimal.Decimal(str(response[str(quote_id)]))
       t@@ -121,24 +252,12 @@ class Exchanger(object):
                        pass
                    self.parent.set_currencies(quote_currencies)
        
       -        def on_failure(*args):
       -            pass
       -
       -        def on_error(*args):
       -            pass
       -
       -        def on_redirect(*args):
       -            pass
       -
                req = UrlRequest(
                    url='https://coinbase.com/api/v1/currencies/exchange_rates',
                    on_success=on_success,
       -            on_failure=on_failure,
       -            on_error=on_error,
       -            on_redirect=on_redirect,
                    timeout=5)
        
       -    def check_blockchain(self):
       +    def update_bc(self):
        
                def _lookup_rate(response, quote_id):
                    return decimal.Decimal(str(response[str(quote_id)]["15m"]))
       t@@ -153,27 +272,69 @@ class Exchanger(object):
                        pass
                    self.parent.set_currencies(quote_currencies)
        
       -        def on_failure(*args):
       -            pass
       +        req = UrlRequest(url='https://blockchain.info/ticker',
       +                        on_success=on_success,
       +                        timeout=5)
        
       -        def on_error(*args):
       -            pass
       +    def update_lb(self):
       +        def _lookup_rate(response, quote_id):
       +            return decimal.Decimal(response[str(quote_id)]["rates"]["last"])
        
       -        def on_redirect(*args):
       -            pass
       +        def on_success(request, response):
       +            quote_currencies = {}
       +            try:
       +                for r in response:
       +                    quote_currencies[r] = _lookup_rate(response, r)
       +                self.quote_currencies = quote_currencies
       +            except KeyError:
       +                pass
       +            self.parent.set_currencies(quote_currencies)
        
       -        req = UrlRequest(url='https://blockchain.info/ticker',
       +        req = UrlRequest(
       +            url='https://localbitcoins.com/bitcoinaverage/ticker-all-currencies/',
       +            on_success=on_success,
       +            timeout=5)
       +
       +
       +    def update_ba(self):
       +
       +        def on_success(request, response):
       +            quote_currencies = {}
       +            try:
       +                for r in response:
       +                    quote_currencies[r] = decimal.Decimal(response[r][u'last'])
       +                self.quote_currencies = quote_currencies
       +            except TypeError:
       +                pass
       +            self.parent.set_currencies(quote_currencies)
       +
       +        req = UrlRequest(url='https://api.bitcoinaverage.com/ticker/global/all',
       +                        on_success=on_success,
       +                        timeout=5)
       +
       +    def update_bv(self):
       +
       +        def on_success(request, response):
       +            quote_currencies = {}
       +            try:
       +                for r in response["BTC"]:
       +                    quote_currencies[r] = decimal.Decimal(response['BTC'][r])
       +                self.quote_currencies = quote_currencies
       +            except KeyError:
       +                pass
       +            self.parent.set_currencies(quote_currencies)
       +
       +        req = UrlRequest(url='https://api.bitcoinvenezuela.com/',
                                on_success=on_success,
       -                        on_failure=on_failure,
       -                        on_error=on_error,
       -                        on_redirect=on_redirect,
                                timeout=5)
        
            def start(self):
       -        # check every 5 seconds
       -        self.check_rates(0)
       -        Clock.schedule_interval(self.check_rates, 5)
       +        # check rates every few seconds
       +        self.update_rate(0)
       +        # check every few seconds
       +        Clock.unschedule(self.update_rate)
       +        Clock.schedule_interval(self.update_rate, 20)
        
            def stop(self):
       -        Clock.unschedule(self.check_rates)
       +        Clock.unschedule(self.update_rate)
        
   DIR diff --git a/lib/util.py b/lib/util.py
       t@@ -142,6 +142,13 @@ def user_dir():
            elif "LOCALAPPDATA" in os.environ:
                return os.path.join(os.environ["LOCALAPPDATA"], "Electrum")
            elif 'ANDROID_DATA' in os.environ:
       +        try:
       +            import jnius
       +            env  = jnius.autoclass('android.os.Environment')
       +            _dir =  env.getExternalStorageDirectory().getPath()
       +            return _dir + '/electrum/'
       +        except ImportError:
       +            pass
                return "/sdcard/electrum/"
            else:
                #raise Exception("No home directory found in environment variables.")