URI: 
       tinclude NFC changes required for transferring data - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit cd4f8a074c7afd0380b0bc6ed92ed477bd10477d
   DIR parent f2fc18fe327c5c8f0fe2bdb2fe8f7f57f623ccfa
  HTML Author: akshayaurora <akshayaurora@gmail.com>
       Date:   Fri,  1 Aug 2014 21:39:34 +0530
       
       include NFC changes required for transferring data
       
       Diffstat:
         M gui/kivy/main_window.py             |      39 ++++++++++++++++++-------------
         M gui/kivy/nfc_scanner/__init__.py    |      23 ++++++++++++-----------
         M gui/kivy/nfc_scanner/scanner_andro… |     199 +++++++++++++++++++++++++++----
         M gui/kivy/nfc_scanner/scanner_dummy… |      15 +++++++++++++++
         M gui/kivy/tools/blacklist.txt        |       8 ++++----
         M gui/kivy/tools/buildozer.spec       |       6 +++---
         M gui/kivy/uix/dialogs/new_contact.py |       1 -
         M gui/kivy/uix/ui_screens/mainscreen… |       1 +
       
       8 files changed, 236 insertions(+), 56 deletions(-)
       ---
   DIR diff --git a/gui/kivy/main_window.py b/gui/kivy/main_window.py
       t@@ -4,6 +4,11 @@ import datetime
        from electrum import WalletStorage, Wallet
        from electrum.i18n import _, set_language
        
       +from kivy.config import Config
       +Config.set('modules', 'screen', 'droid2')
       +Config.set('graphics', 'width', '480')
       +Config.set('graphics', 'height', '840')
       +
        from kivy.app import App
        from kivy.core.window import Window
        from kivy.logger import Logger
       t@@ -30,9 +35,9 @@ inch = None
        util = False
        re = None
        
       -# register widget cache for keeping memory down timeout to 4 minutes to cache
       +# register widget cache for keeping memory down timeout to forever to cache
        # the data
       -Cache.register('electrum_widgets', timeout=240)
       +Cache.register('electrum_widgets', timeout=0)
        
        class ElectrumWindow(App):
        
       t@@ -375,19 +380,23 @@ class ElectrumWindow(App):
                                 module='electrum_gui.kivy.uix.screens')
                Factory.register('ScreenDashboard',
                                 module='electrum_gui.kivy.uix.screens')
       -        Factory.register('EffectWidget',
       -                         module='electrum_gui.kivy.uix.effectwidget')
       -
       -        # load and focus the ui
       -        #Load mainscreen
       -
       +        #Factory.register('EffectWidget',
       +        #                 module='electrum_gui.kivy.uix.effectwidget')
                Factory.register('QRCodeWidget',
                                 module='electrum_gui.kivy.uix.qrcodewidget')
                Factory.register('MainScreen',
                                 module='electrum_gui.kivy.uix.screens')
                Factory.register('CSpinner',
                                 module='electrum_gui.kivy.uix.screens')
       +        # preload widgets. Remove this if you want to load the widgets on demand
       +        Cache.append('electrum_widgets', 'AnimatedPopup', Factory.AnimatedPopup())
       +        Cache.append('electrum_widgets', 'TabbedCarousel', Factory.TabbedCarousel())
       +        Cache.append('electrum_widgets', 'QRCodeWidget', Factory.QRCodeWidget())
       +        Cache.append('electrum_widgets', 'CSpinner', Factory.CSpinner())
       +
        
       +        # load and focus the ui
       +        #Load mainscreen
                dr = Builder.load_file('gui/kivy/uix/ui_screens/mainscreen.kv')
                self.root.add_widget(dr)
                self.root.manager = manager = dr.ids.manager
       t@@ -1032,7 +1041,7 @@ class ElectrumWindow(App):
        
                # populate
                def set_address(*l):
       -            content = screen_send.content.ids
       +            content = screen_send.ids
                    content.payto_e.text = m_addr
                    content.message_e.text = message
                    if amount:
       t@@ -1051,7 +1060,7 @@ class ElectrumWindow(App):
                # switch_to the send screen
                tabs.ids.panel.switch_to(tabs.ids.tab_send)
        
       -        content = screen_send.content.ids
       +        content = screen_send.ids
                if content:
                    self.set_frozen(content, False)
                screen_send.screen_label.text = _("please wait...")
       t@@ -1064,12 +1073,11 @@ class ElectrumWindow(App):
                # switch_to the send screen
                tabs.ids.panel.switch_to(tabs.ids.tab_send)
        
       -        content = screen_send.content
                self.set_frozen(content, True)
        
       -        content.ids.payto_e.text = self.gui_object.payment_request.domain
       -        content.ids.amount_e.text = self.format_amount(self.gui_object.payment_request.get_amount())
       -        content.ids.message_e.text = self.gui_object.payment_request.memo
       +        screen_send.ids.payto_e.text = self.gui_object.payment_request.domain
       +        screen_send.ids.amount_e.text = self.format_amount(self.gui_object.payment_request.get_amount())
       +        screen_send.ids.message_e.text = self.gui_object.payment_request.memo
        
                # wait for screen to load
                Clock.schedule_once(set_address, .5)
       t@@ -1275,4 +1283,4 @@ class ElectrumWindow(App):
                info_bubble.message = text
                if not pos:
                        pos = (win.center[0], win.center[1] - (info_bubble.height/2))
       -        info_bubble.show(pos, duration, width, modal=modal, exit=exit)
       -\ No newline at end of file
       +        info_bubble.show(pos, duration, width, modal=modal, exit=exit)
   DIR diff --git a/gui/kivy/nfc_scanner/__init__.py b/gui/kivy/nfc_scanner/__init__.py
       t@@ -1,18 +1,18 @@
       -'''
       -'''
       -from kivy.core import core_select_lib
       -from kivy.uix.widget import Widget
       -from kivy.properties import ObjectProperty
       -from kivy.factory import Factory
       -
        __all__ = ('NFCBase', 'NFCScanner')
        
        class NFCBase(Widget):
       +    ''' This is the base Abstract definition class that the actual hardware dependent
       +    implementations would be based on. If you want to define a feature that is
       +    accissible and implemented by every platform implementation then define that
       +    method in this class.
       +    '''
        
            payload = ObjectProperty(None)
       +    '''This is the data gotten from the tag. 
       +    '''
        
            def nfc_init(self):
       -        ''' Initialize the adapter
       +        ''' Initialize the adapter.
                '''
                pass
        
       t@@ -27,17 +27,18 @@ class NFCBase(Widget):
                pass
        
            def nfc_enable_exchange(self, data):
       -        ''' Start sending data
       +        ''' Enable P2P Ndef exchange
                '''
                pass
        
            def nfc_disable_exchange(self):
       -        ''' Disable/Stop ndef exchange
       +        ''' Disable/Stop P2P Ndef exchange
                '''
                pass
        
        # load NFCScanner implementation
        
       -NFCScanner = core_select_lib('nfc_scanner', (
       +NFCScanner = core_select_lib('nfc_manager', (
       +    # keep the dummy implementtation as the last one to make it the fallback provider.NFCScanner = core_select_lib('nfc_scanner', (
            ('android', 'scanner_android', 'ScannerAndroid'),
            ('dummy', 'scanner_dummy', 'ScannerDummy')), True, 'electrum_gui.kivy')
   DIR diff --git a/gui/kivy/nfc_scanner/scanner_android.py b/gui/kivy/nfc_scanner/scanner_android.py
       t@@ -1,86 +1,243 @@
       +'''This is the Android implementatoin of NFC Scanning using the
       +built in NFC adapter of some android phones.
       +'''
       +
       +from kivy.app import App
       +from kivy.clock import Clock
       +#Detect which platform we are on
        from kivy.utils import platform
        if platform != 'android':
            raise ImportError
       +import threading
        
        from electrum_gui.kivy.nfc_scanner import NFCBase
        from jnius import autoclass, cast
        from android.runnable import run_on_ui_thread
        from android import activity
        
       +BUILDVERSION = autoclass('android.os.Build$VERSION').SDK_INT
        NfcAdapter = autoclass('android.nfc.NfcAdapter')
        PythonActivity = autoclass('org.renpy.android.PythonActivity')
       +JString = autoclass('java.lang.String')
       +Charset = autoclass('java.nio.charset.Charset')
       +locale = autoclass('java.util.Locale')
        Intent = autoclass('android.content.Intent')
        IntentFilter = autoclass('android.content.IntentFilter')
        PendingIntent = autoclass('android.app.PendingIntent')
       +Ndef = autoclass('android.nfc.tech.Ndef')
        NdefRecord = autoclass('android.nfc.NdefRecord')
        NdefMessage = autoclass('android.nfc.NdefMessage')
        
       +app = None
       +
       +
       +
        class ScannerAndroid(NFCBase):
       +    ''' This is the class responsible for handling the interace with the
       +    Android NFC adapter. See Module Documentation for deatils.
       +    '''
       +
       +    name = 'NFCAndroid'
        
            def nfc_init(self):
       -        # print 'nfc_init()'
       +        ''' This is where we initialize NFC adapter.
       +        '''
       +        # Initialize NFC
       +        global app
       +        app = App.get_running_app()
        
       -        # print 'configure nfc'
       +        # Make sure we are listening to new intent 
       +        activity.bind(on_new_intent=self.on_new_intent)
       +
       +        # Configure nfc
                self.j_context = context = PythonActivity.mActivity
                self.nfc_adapter = NfcAdapter.getDefaultAdapter(context)
       +        # Check if adapter exists
       +        if not self.nfc_adapter:
       +            return False
       +        
       +        # specify that we want our activity to remain on top whan a new intent
       +        # is fired
                self.nfc_pending_intent = PendingIntent.getActivity(context, 0,
                    Intent(context, context.getClass()).addFlags(
                        Intent.FLAG_ACTIVITY_SINGLE_TOP), 0)
        
       -        # print 'p2p filter'
       +        # Filter for different types of action, by default we enable all.
       +        # These are only for handling different NFC technologies when app is in foreground
                self.ndef_detected = IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED)
       -        self.ndef_detected.addDataType('text/plain')
       -        self.ndef_exchange_filters = [self.ndef_detected]
       +        #self.tech_detected = IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED)
       +        #self.tag_detected = IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED)
       +
       +        # setup tag discovery for ourt tag type
       +        try:
       +            self.ndef_detected.addCategory(Intent.CATEGORY_DEFAULT)
       +            # setup the foreground dispatch to detect all mime types
       +            self.ndef_detected.addDataType('*/*')
       +
       +            self.ndef_exchange_filters = [self.ndef_detected]
       +        except Exception as err:
       +            raise Exception(repr(err))
       +        return True
       +
       +    def get_ndef_details(self, tag):
       +        ''' Get all the details from the tag.
       +        '''
       +        details = {}
       +
       +        try:
       +            #print 'id'
       +            details['uid'] = ':'.join(['{:02x}'.format(bt & 0xff) for bt in tag.getId()])
       +            #print 'technologies'
       +            details['Technologies'] = tech_list = [tech.split('.')[-1] for tech in tag.getTechList()]
       +            #print 'get NDEF tag details'
       +            ndefTag = cast('android.nfc.tech.Ndef', Ndef.get(tag))
       +            #print 'tag size'
       +            details['MaxSize'] = ndefTag.getMaxSize()
       +            #details['usedSize'] = '0'
       +            #print 'is tag writable?'
       +            details['writable'] = ndefTag.isWritable()
       +            #print 'Data format'
       +            # Can be made readonly
       +            # get NDEF message details
       +            ndefMesg = ndefTag.getCachedNdefMessage()
       +            # get size of current records
       +            details['consumed'] = len(ndefMesg.toByteArray())
       +            #print 'tag type'
       +            details['Type'] = ndefTag.getType()
       +
       +            # check if tag is empty
       +            if not ndefMesg:
       +                details['Message'] = None
       +                return details
       +
       +            ndefrecords =  ndefMesg.getRecords()
       +            length = len(ndefrecords)
       +            #print 'length', length
       +            # will contain the NDEF record types
       +            recTypes = []
       +            self.
       +            for record in ndefrecords:
       +                recTypes.append({
       +                    'type': ''.join(map(unichr, record.getType())),
       +                    'payload': ''.join(map(unichr, record.getPayload()))
       +                    })
       +
       +            details['recTypes'] = recTypes
       +        except Exception as err:
       +            print str(err)
       +
       +        return details
        
            def on_new_intent(self, intent):
       -        # print 'on_new_intent()', intent.getAction()
       -        if intent.getAction() != NfcAdapter.ACTION_NDEF_DISCOVERED:
       -            # print 'unknow action, avoid.'
       +        ''' This functions is called when the application receives a
       +        new intent, for the ones the application has registered previously,
       +        either in the manifest or in the foreground dispatch setup in the
       +        nfc_init function above. 
       +        '''
       +
       +        action_list = (NfcAdapter.ACTION_NDEF_DISCOVERED,)
       +        # get TAG
       +        #tag = cast('android.nfc.Tag', intent.getParcelableExtra(NfcAdapter.EXTRA_TAG))
       +
       +        #details = self.get_ndef_details(tag)
       +
       +        if intent.getAction() not in action_list:
       +            print 'unknow action, avoid.'
                    return
        
                rawmsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)
       -        # print 'raw messages', rawmsgs
                if not rawmsgs:
                    return
       -
                for message in rawmsgs:
                    message = cast(NdefMessage, message)
       -            # print 'got message', message
                    payload = message.getRecords()[0].getPayload()
       -            self.payload = payload
                    print 'payload: {}'.format(''.join(map(chr, payload)))
        
            def nfc_disable(self):
       -        # print 'nfc_enable()'
       -        activity.bind(on_new_intent=self.on_new_intent)
       +        '''Disable app from handling tags.
       +        '''
       +        self.disable_foreground_dispatch()
        
            def nfc_enable(self):
       -        # print 'nfc_enable()'
       -        activity.bind(on_new_intent=self.on_new_intent)
       +        '''Enable app to handle tags when app in foreground.
       +        '''
       +        self.enable_foreground_dispatch()
       +
       +    def create_AAR(self):
       +        '''Create the record responsible for linking our application to the tag.
       +        '''
       +        return NdefRecord.createApplicationRecord(JString("org.electrum.kivy"))
       +
       +    def create_TNF_EXTERNAL(self, data):
       +        '''Create our actual payload record.
       +        '''
       +        if BUILDVERSION >= 14:
       +            domain = "org.electrum"
       +            stype = "externalType"
       +            extRecord = NdefRecord.createExternal(domain, stype, data)
       +        else:
       +            # Creating the NdefRecord manually:
       +            extRecord = NdefRecord(
       +                NdefRecord.TNF_EXTERNAL_TYPE,
       +                "org.electrum:externalType",
       +                '',
       +                data)
       +        return extRecord
       +
       +    def create_ndef_message(self, *recs):
       +        ''' Create the Ndef message that will written to tag
       +        '''
       +        records = []
       +        for record in recs:
       +            if record:
       +                records.append(record)
       +
       +        return NdefMessage(records)
       +
       +
       +    @run_on_ui_thread
       +    def disable_foreground_dispatch(self):
       +        '''Disable foreground dispatch when app is paused.
       +        '''
       +        self.nfc_adapter.disableForegroundDispatch(self.j_context)
       +
       +    @run_on_ui_thread
       +    def enable_foreground_dispatch(self):
       +        '''Start listening for new tags
       +        '''
       +        self.nfc_adapter.enableForegroundDispatch(self.j_context,
       +                self.nfc_pending_intent, self.ndef_exchange_filters, self.ndef_tech_list)
        
            @run_on_ui_thread
            def _nfc_enable_ndef_exchange(self, data):
       -        # print 'create record'
       +        # Enable p2p exchange
       +        # Create record
                ndef_record = NdefRecord(
                        NdefRecord.TNF_MIME_MEDIA,
       -                'text/plain', '', data)
       -        # print 'create message'
       +                'org.electrum.kivy', '', data)
       +        
       +        # Create message
                ndef_message = NdefMessage([ndef_record])
        
       -        # print 'enable ndef push'
       +        # Enable ndef push
                self.nfc_adapter.enableForegroundNdefPush(self.j_context, ndef_message)
        
       -        # print 'enable dispatch', self.j_context, self.nfc_pending_intent
       +        # Enable dispatch
                self.nfc_adapter.enableForegroundDispatch(self.j_context,
                        self.nfc_pending_intent, self.ndef_exchange_filters, [])
        
            @run_on_ui_thread
            def _nfc_disable_ndef_exchange(self):
       +        # Disable p2p exchange
                self.nfc_adapter.disableForegroundNdefPush(self.j_context)
                self.nfc_adapter.disableForegroundDispatch(self.j_context)
        
            def nfc_enable_exchange(self, data):
       +        '''Enable Ndef exchange for p2p
       +        '''
                self._nfc_enable_ndef_exchange()
        
            def nfc_disable_exchange(self):
       +        ''' Disable Ndef exchange for p2p
       +        '''
                self._nfc_disable_ndef_exchange()
   DIR diff --git a/gui/kivy/nfc_scanner/scanner_dummy.py b/gui/kivy/nfc_scanner/scanner_dummy.py
       t@@ -5,16 +5,31 @@ from kivy.clock import Clock
        from kivy.logger import Logger
        
        class ScannerDummy(NFCBase):
       +    '''This is the dummy interface that gets selected in case any other
       +    hardware interface to NFC is not available.
       +    '''
        
            _initialised = False
        
       +    name = 'NFCDummy'
       +
            def nfc_init(self):
                # print 'nfc_init()'
        
                Logger.debug('NFC: configure nfc')
                self._initialised = True
       +        self.nfc_enable()
       +        return True
        
            def on_new_intent(self, dt):
       +        tag_info = {'type': 'dymmy',
       +                    'message': 'dummy',
       +                    'extra details': None}
       +
       +        # let Main app know that a tag has been detected
       +        app = App.get_running_app()
       +        app.tag_discovered(tag_info)
       +        app.show_info('New tag detected.', duration=2)
                Logger.debug('NFC: got new dummy tag')
        
            def nfc_enable(self):
   DIR diff --git a/gui/kivy/tools/blacklist.txt b/gui/kivy/tools/blacklist.txt
       t@@ -60,14 +60,14 @@ wsgiref/*
        hotshot/*
        pydoc_data/*
        tty.pyo
       -anydbm.pyo
       +#anydbm.pyo
        nturl2path.pyo
        LICENCE.txt
        macurl2path.pyo
        dummy_threading.pyo
        audiodev.pyo
        antigravity.pyo
       -dumbdbm.pyo
       +#dumbdbm.pyo
        sndhdr.pyo
        __phello__.foo.pyo
        sunaudio.pyo
       t@@ -93,7 +93,7 @@ plat-linux3/regen
        
        #>sqlite3
        # conditionnal include depending if some recipes are included or not.
       -sqlite3/*
       -lib-dynload/_sqlite3.so
       +#sqlite3/*
       +#lib-dynload/_sqlite3.so
        #<sqlite3
        
   DIR diff --git a/gui/kivy/tools/buildozer.spec b/gui/kivy/tools/buildozer.spec
       t@@ -32,7 +32,7 @@ source.exclude_exts = spec
        version = 1.9.8
        
        # (list) Application requirements
       -requirements = pil, qrcode, ecdsa, pbkdf2, openssl, pyopenssl, pyasn, pyasn-modules,  plyer==master, kivy==master
       +requirements = tlslite, openssl, pyopenssl, pil, qrcode, ecdsa, pbkdf2, pyasn1, pyasn1-modules,  plyer==master, kivy==master
        
        # (str) Presplash of the application
        presplash.filename = %(source.dir)s/gui/kivy/theming/splash.png
       t@@ -52,7 +52,7 @@ fullscreen = False
        #
        
        # (list) Permissions
       -android.permissions = INTERNET, WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE , CAMERA, NFC
       +android.permissions = INTERNET, WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE, CAMERA, NFC
        # (int) Android API to use
        #android.api = 14
        
       t@@ -100,7 +100,7 @@ android.branch = master
        #android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png
        
        # (str) XML file to include as an intent filters in <activity> tag
       -#android.manifest.intent_filters =
       +#android.manifest.intent_filters = nfc_filter.xml
        
        # (list) Android additionnal libraries to copy into libs/armeabi
        android.add_libs_armeabi = lib/android/*.so
   DIR diff --git a/gui/kivy/uix/dialogs/new_contact.py b/gui/kivy/uix/dialogs/new_contact.py
       t@@ -1,7 +1,6 @@
        from kivy.app import App
        from kivy.factory import Factory
        from kivy.properties import ObjectProperty
       -from kivy.cache import Cache
        
        Factory.register('QrScannerDialog', module='electrum_gui.kivy.uix.dialogs.qr_scanner')
        
   DIR diff --git a/gui/kivy/uix/ui_screens/mainscreen.kv b/gui/kivy/uix/ui_screens/mainscreen.kv
       t@@ -489,6 +489,7 @@
        <ScreenReceive>
            mode: 'qr'
            name: 'receive'
       +    on_mode: if args[1] == 'nfc': from electrum_gui.kivy.nfc_scanner import NFCScanner
            action_view: Factory.ReceiveActionView()
            on_activate:
                self.ids.toggle_qr.state = 'down'