akshayaurora
11 years ago
committed by
ThomasV
8 changed files with 236 additions and 55 deletions
@ -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() |
|||
|
Loading…
Reference in new issue