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 |
from kivy.utils import platform |
||||
if platform != 'android': |
if platform != 'android': |
||||
raise ImportError |
raise ImportError |
||||
|
import threading |
||||
|
|
||||
from electrum_gui.kivy.nfc_scanner import NFCBase |
from electrum_gui.kivy.nfc_scanner import NFCBase |
||||
from jnius import autoclass, cast |
from jnius import autoclass, cast |
||||
from android.runnable import run_on_ui_thread |
from android.runnable import run_on_ui_thread |
||||
from android import activity |
from android import activity |
||||
|
|
||||
|
BUILDVERSION = autoclass('android.os.Build$VERSION').SDK_INT |
||||
NfcAdapter = autoclass('android.nfc.NfcAdapter') |
NfcAdapter = autoclass('android.nfc.NfcAdapter') |
||||
PythonActivity = autoclass('org.renpy.android.PythonActivity') |
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') |
Intent = autoclass('android.content.Intent') |
||||
IntentFilter = autoclass('android.content.IntentFilter') |
IntentFilter = autoclass('android.content.IntentFilter') |
||||
PendingIntent = autoclass('android.app.PendingIntent') |
PendingIntent = autoclass('android.app.PendingIntent') |
||||
|
Ndef = autoclass('android.nfc.tech.Ndef') |
||||
NdefRecord = autoclass('android.nfc.NdefRecord') |
NdefRecord = autoclass('android.nfc.NdefRecord') |
||||
NdefMessage = autoclass('android.nfc.NdefMessage') |
NdefMessage = autoclass('android.nfc.NdefMessage') |
||||
|
|
||||
|
app = None |
||||
|
|
||||
|
|
||||
|
|
||||
class ScannerAndroid(NFCBase): |
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): |
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.j_context = context = PythonActivity.mActivity |
||||
self.nfc_adapter = NfcAdapter.getDefaultAdapter(context) |
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, |
self.nfc_pending_intent = PendingIntent.getActivity(context, 0, |
||||
Intent(context, context.getClass()).addFlags( |
Intent(context, context.getClass()).addFlags( |
||||
Intent.FLAG_ACTIVITY_SINGLE_TOP), 0) |
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 = IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED) |
||||
self.ndef_detected.addDataType('text/plain') |
#self.tech_detected = IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED) |
||||
self.ndef_exchange_filters = [self.ndef_detected] |
#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): |
def on_new_intent(self, intent): |
||||
# print 'on_new_intent()', intent.getAction() |
''' This functions is called when the application receives a |
||||
if intent.getAction() != NfcAdapter.ACTION_NDEF_DISCOVERED: |
new intent, for the ones the application has registered previously, |
||||
# print 'unknow action, avoid.' |
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 |
return |
||||
|
|
||||
rawmsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES) |
rawmsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES) |
||||
# print 'raw messages', rawmsgs |
|
||||
if not rawmsgs: |
if not rawmsgs: |
||||
return |
return |
||||
|
|
||||
for message in rawmsgs: |
for message in rawmsgs: |
||||
message = cast(NdefMessage, message) |
message = cast(NdefMessage, message) |
||||
# print 'got message', message |
|
||||
payload = message.getRecords()[0].getPayload() |
payload = message.getRecords()[0].getPayload() |
||||
self.payload = payload |
|
||||
print 'payload: {}'.format(''.join(map(chr, payload))) |
print 'payload: {}'.format(''.join(map(chr, payload))) |
||||
|
|
||||
def nfc_disable(self): |
def nfc_disable(self): |
||||
# print 'nfc_enable()' |
'''Disable app from handling tags. |
||||
activity.bind(on_new_intent=self.on_new_intent) |
''' |
||||
|
self.disable_foreground_dispatch() |
||||
|
|
||||
def nfc_enable(self): |
def nfc_enable(self): |
||||
# print 'nfc_enable()' |
'''Enable app to handle tags when app in foreground. |
||||
activity.bind(on_new_intent=self.on_new_intent) |
''' |
||||
|
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 |
@run_on_ui_thread |
||||
def _nfc_enable_ndef_exchange(self, data): |
def _nfc_enable_ndef_exchange(self, data): |
||||
# print 'create record' |
# Enable p2p exchange |
||||
|
# Create record |
||||
ndef_record = NdefRecord( |
ndef_record = NdefRecord( |
||||
NdefRecord.TNF_MIME_MEDIA, |
NdefRecord.TNF_MIME_MEDIA, |
||||
'text/plain', '', data) |
'org.electrum.kivy', '', data) |
||||
# print 'create message' |
|
||||
|
# Create message |
||||
ndef_message = NdefMessage([ndef_record]) |
ndef_message = NdefMessage([ndef_record]) |
||||
|
|
||||
# print 'enable ndef push' |
# Enable ndef push |
||||
self.nfc_adapter.enableForegroundNdefPush(self.j_context, ndef_message) |
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_adapter.enableForegroundDispatch(self.j_context, |
||||
self.nfc_pending_intent, self.ndef_exchange_filters, []) |
self.nfc_pending_intent, self.ndef_exchange_filters, []) |
||||
|
|
||||
@run_on_ui_thread |
@run_on_ui_thread |
||||
def _nfc_disable_ndef_exchange(self): |
def _nfc_disable_ndef_exchange(self): |
||||
|
# Disable p2p exchange |
||||
self.nfc_adapter.disableForegroundNdefPush(self.j_context) |
self.nfc_adapter.disableForegroundNdefPush(self.j_context) |
||||
self.nfc_adapter.disableForegroundDispatch(self.j_context) |
self.nfc_adapter.disableForegroundDispatch(self.j_context) |
||||
|
|
||||
def nfc_enable_exchange(self, data): |
def nfc_enable_exchange(self, data): |
||||
|
'''Enable Ndef exchange for p2p |
||||
|
''' |
||||
self._nfc_enable_ndef_exchange() |
self._nfc_enable_ndef_exchange() |
||||
|
|
||||
def nfc_disable_exchange(self): |
def nfc_disable_exchange(self): |
||||
|
''' Disable Ndef exchange for p2p |
||||
|
''' |
||||
self._nfc_disable_ndef_exchange() |
self._nfc_disable_ndef_exchange() |
||||
|
Loading…
Reference in new issue