Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
M
meser
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Muhammad Suryono
meser
Commits
dbdfc6c5
Commit
dbdfc6c5
authored
Sep 02, 2020
by
Muhammad Suryono
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update add library NFC
parent
440344c6
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
430 additions
and
0 deletions
+430
-0
NdefMessageParser.java
...ava/com/yono/messeripos/nfc/parser/NdefMessageParser.java
+43
-0
ParsedNdefRecord.java
...java/com/yono/messeripos/nfc/record/ParsedNdefRecord.java
+5
-0
SmartPoster.java
...main/java/com/yono/messeripos/nfc/record/SmartPoster.java
+186
-0
TextRecord.java
.../main/java/com/yono/messeripos/nfc/record/TextRecord.java
+76
-0
UriRecord.java
...c/main/java/com/yono/messeripos/nfc/record/UriRecord.java
+120
-0
No files found.
app/src/main/java/com/yono/messeripos/nfc/parser/NdefMessageParser.java
0 → 100644
View file @
dbdfc6c5
package
com
.
yono
.
messeripos
.
nfc
.
parser
;
import
android.nfc.NdefMessage
;
import
android.nfc.NdefRecord
;
import
com.yono.nfc.record.ParsedNdefRecord
;
import
com.yono.nfc.record.SmartPoster
;
import
com.yono.nfc.record.TextRecord
;
import
com.yono.nfc.record.UriRecord
;
import
java.util.ArrayList
;
import
java.util.List
;
public
class
NdefMessageParser
{
public
NdefMessageParser
()
{
}
public
static
List
<
ParsedNdefRecord
>
parse
(
NdefMessage
message
)
{
return
getRecords
(
message
.
getRecords
());
}
public
static
List
<
ParsedNdefRecord
>
getRecords
(
NdefRecord
[]
records
)
{
List
<
ParsedNdefRecord
>
elements
=
new
ArrayList
<
ParsedNdefRecord
>();
for
(
final
NdefRecord
record
:
records
)
{
if
(
UriRecord
.
isUri
(
record
))
{
elements
.
add
(
UriRecord
.
parse
(
record
));
}
else
if
(
TextRecord
.
isText
(
record
))
{
elements
.
add
(
TextRecord
.
parse
(
record
));
}
else
if
(
SmartPoster
.
isPoster
(
record
))
{
elements
.
add
(
SmartPoster
.
parse
(
record
));
}
else
{
elements
.
add
(
new
ParsedNdefRecord
()
{
public
String
str
()
{
return
new
String
(
record
.
getPayload
());
}
});
}
}
return
elements
;
}
}
app/src/main/java/com/yono/messeripos/nfc/record/ParsedNdefRecord.java
0 → 100644
View file @
dbdfc6c5
package
com
.
yono
.
messeripos
.
nfc
.
record
;
public
interface
ParsedNdefRecord
{
String
str
();
}
app/src/main/java/com/yono/messeripos/nfc/record/SmartPoster.java
0 → 100644
View file @
dbdfc6c5
package
com
.
yono
.
messeripos
.
nfc
.
record
;
import
android.nfc.FormatException
;
import
android.nfc.NdefMessage
;
import
android.nfc.NdefRecord
;
import
com.google.common.base.Charsets
;
import
com.google.common.base.Preconditions
;
import
com.google.common.collect.ImmutableMap
;
import
com.google.common.collect.Iterables
;
import
com.yono.nfc.parser.NdefMessageParser
;
import
java.util.Arrays
;
import
java.util.NoSuchElementException
;
public
class
SmartPoster
implements
ParsedNdefRecord
{
/**
* NFC Forum Smart Poster Record Type Definition section 3.2.1.
*
* "The Title record for the service (there can be many of these in
* different languages, but a language MUST NOT be repeated). This record is
* optional."
*/
private
final
TextRecord
mTitleRecord
;
/**
* NFC Forum Smart Poster Record Type Definition section 3.2.1.
*
* "The URI record. This is the core of the Smart Poster, and all other
* records are just metadata about this record. There MUST be one URI record
* and there MUST NOT be more than one."
*/
private
final
UriRecord
mUriRecord
;
/**
* NFC Forum Smart Poster Record Type Definition section 3.2.1.
*
* "The Action record. This record describes how the service should be
* treated. For example, the action may indicate that the device should save
* the URI as a bookmark or open a browser. The Action record is optional.
* If it does not exist, the device may decide what to do with the service.
* If the action record exists, it should be treated as a strong suggestion;
* the UI designer may ignore it, but doing so will induce a different user
* experience from device to device."
*/
private
final
RecommendedAction
mAction
;
/**
* NFC Forum Smart Poster Record Type Definition section 3.2.1.
*
* "The Type record. If the URI references an external entity (e.g., via a
* URL), the Type record may be used to declare the MIME type of the entity.
* This can be used to tell the mobile device what kind of an object it can
* expect before it opens the connection. The Type record is optional."
*/
private
final
String
mType
;
public
SmartPoster
(
UriRecord
uri
,
TextRecord
title
,
RecommendedAction
action
,
String
type
)
{
mUriRecord
=
Preconditions
.
checkNotNull
(
uri
);
mTitleRecord
=
title
;
mAction
=
Preconditions
.
checkNotNull
(
action
);
mType
=
type
;
}
public
UriRecord
getUriRecord
()
{
return
mUriRecord
;
}
/**
* Returns the title of the smart poster. This may be {@code null}.
*/
public
TextRecord
getTitle
()
{
return
mTitleRecord
;
}
public
static
SmartPoster
parse
(
NdefRecord
record
)
{
Preconditions
.
checkArgument
(
record
.
getTnf
()
==
NdefRecord
.
TNF_WELL_KNOWN
);
Preconditions
.
checkArgument
(
Arrays
.
equals
(
record
.
getType
(),
NdefRecord
.
RTD_SMART_POSTER
));
try
{
NdefMessage
subRecords
=
new
NdefMessage
(
record
.
getPayload
());
return
parse
(
subRecords
.
getRecords
());
}
catch
(
FormatException
e
)
{
throw
new
IllegalArgumentException
(
e
);
}
}
public
static
SmartPoster
parse
(
NdefRecord
[]
recordsRaw
)
{
try
{
Iterable
<
ParsedNdefRecord
>
records
=
NdefMessageParser
.
getRecords
(
recordsRaw
);
UriRecord
uri
=
Iterables
.
getOnlyElement
(
Iterables
.
filter
(
records
,
UriRecord
.
class
));
TextRecord
title
=
getFirstIfExists
(
records
,
TextRecord
.
class
);
RecommendedAction
action
=
parseRecommendedAction
(
recordsRaw
);
String
type
=
parseType
(
recordsRaw
);
return
new
SmartPoster
(
uri
,
title
,
action
,
type
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
IllegalArgumentException
(
e
);
}
}
public
static
boolean
isPoster
(
NdefRecord
record
)
{
try
{
parse
(
record
);
return
true
;
}
catch
(
IllegalArgumentException
e
)
{
return
false
;
}
}
@Override
public
String
str
()
{
if
(
mTitleRecord
!=
null
)
{
return
mTitleRecord
.
str
()
+
"\n"
+
mUriRecord
.
str
();
}
else
{
return
mUriRecord
.
str
();
}
}
/**
* Returns the first element of {@code elements} which is an instance of
* {@code type}, or {@code null} if no such element exists.
*/
private
static
<
T
>
T
getFirstIfExists
(
Iterable
<?>
elements
,
Class
<
T
>
type
)
{
Iterable
<
T
>
filtered
=
Iterables
.
filter
(
elements
,
type
);
T
instance
=
null
;
if
(!
Iterables
.
isEmpty
(
filtered
))
{
instance
=
Iterables
.
get
(
filtered
,
0
);
}
return
instance
;
}
public
enum
RecommendedAction
{
UNKNOWN
((
byte
)
-
1
),
DO_ACTION
((
byte
)
0
),
SAVE_FOR_LATER
((
byte
)
1
),
OPEN_FOR_EDITING
(
(
byte
)
2
);
private
static
final
ImmutableMap
<
Byte
,
RecommendedAction
>
LOOKUP
;
static
{
ImmutableMap
.
Builder
<
Byte
,
RecommendedAction
>
builder
=
ImmutableMap
.
builder
();
for
(
RecommendedAction
action
:
RecommendedAction
.
values
())
{
builder
.
put
(
action
.
getByte
(),
action
);
}
LOOKUP
=
builder
.
build
();
}
private
final
byte
mAction
;
private
RecommendedAction
(
byte
val
)
{
this
.
mAction
=
val
;
}
private
byte
getByte
()
{
return
mAction
;
}
}
private
static
NdefRecord
getByType
(
byte
[]
type
,
NdefRecord
[]
records
)
{
for
(
NdefRecord
record
:
records
)
{
if
(
Arrays
.
equals
(
type
,
record
.
getType
()))
{
return
record
;
}
}
return
null
;
}
private
static
final
byte
[]
ACTION_RECORD_TYPE
=
new
byte
[]
{
'a'
,
'c'
,
't'
};
private
static
RecommendedAction
parseRecommendedAction
(
NdefRecord
[]
records
)
{
NdefRecord
record
=
getByType
(
ACTION_RECORD_TYPE
,
records
);
if
(
record
==
null
)
{
return
RecommendedAction
.
UNKNOWN
;
}
byte
action
=
record
.
getPayload
()[
0
];
if
(
RecommendedAction
.
LOOKUP
.
containsKey
(
action
))
{
return
RecommendedAction
.
LOOKUP
.
get
(
action
);
}
return
RecommendedAction
.
UNKNOWN
;
}
private
static
final
byte
[]
TYPE_TYPE
=
new
byte
[]
{
't'
};
private
static
String
parseType
(
NdefRecord
[]
records
)
{
NdefRecord
type
=
getByType
(
TYPE_TYPE
,
records
);
if
(
type
==
null
)
{
return
null
;
}
return
new
String
(
type
.
getPayload
(),
Charsets
.
UTF_8
);
}
}
app/src/main/java/com/yono/messeripos/nfc/record/TextRecord.java
0 → 100644
View file @
dbdfc6c5
package
com
.
yono
.
messeripos
.
nfc
.
record
;
import
android.nfc.NdefRecord
;
import
com.google.common.base.Preconditions
;
import
java.io.UnsupportedEncodingException
;
import
java.util.Arrays
;
public
class
TextRecord
implements
ParsedNdefRecord
{
private
final
String
mLanguageCode
;
private
final
String
mText
;
public
TextRecord
(
String
languageCode
,
String
text
)
{
mLanguageCode
=
Preconditions
.
checkNotNull
(
languageCode
);
mText
=
Preconditions
.
checkNotNull
(
text
);
}
@Override
public
String
str
()
{
return
mText
;
}
public
String
getText
()
{
return
mText
;
}
/**
* Returns the ISO/IANA language code associated with this text element.
*/
public
String
getLanguageCode
()
{
return
mLanguageCode
;
}
// TODO: deal with text fields which span multiple NdefRecords
public
static
TextRecord
parse
(
NdefRecord
record
)
{
Preconditions
.
checkArgument
(
record
.
getTnf
()
==
NdefRecord
.
TNF_WELL_KNOWN
);
Preconditions
.
checkArgument
(
Arrays
.
equals
(
record
.
getType
(),
NdefRecord
.
RTD_TEXT
));
try
{
byte
[]
payload
=
record
.
getPayload
();
/*
* payload[0] contains the "Status Byte Encodings" field, per the
* NFC Forum "Text Record Type Definition" section 3.2.1.
*
* bit7 is the Text Encoding Field.
*
* if (Bit_7 == 0): The text is encoded in UTF-8 if (Bit_7 == 1):
* The text is encoded in UTF16
*
* Bit_6 is reserved for future use and must be set to zero.
*
* Bits 5 to 0 are the length of the IANA language code.
*/
String
textEncoding
=
((
payload
[
0
]
&
0200
)
==
0
)
?
"UTF-8"
:
"UTF-16"
;
int
languageCodeLength
=
payload
[
0
]
&
0077
;
String
languageCode
=
new
String
(
payload
,
1
,
languageCodeLength
,
"US-ASCII"
);
String
text
=
new
String
(
payload
,
languageCodeLength
+
1
,
payload
.
length
-
languageCodeLength
-
1
,
textEncoding
);
return
new
TextRecord
(
languageCode
,
text
);
}
catch
(
UnsupportedEncodingException
e
)
{
// should never happen unless we get a malformed tag.
throw
new
IllegalArgumentException
(
e
);
}
}
public
static
boolean
isText
(
NdefRecord
record
)
{
try
{
parse
(
record
);
return
true
;
}
catch
(
IllegalArgumentException
e
)
{
return
false
;
}
}
}
app/src/main/java/com/yono/messeripos/nfc/record/UriRecord.java
0 → 100644
View file @
dbdfc6c5
package
com
.
yono
.
messeripos
.
nfc
.
record
;
import
android.annotation.SuppressLint
;
import
android.net.Uri
;
import
android.nfc.NdefRecord
;
import
androidx.core.util.Preconditions
;
import
com.google.common.collect.BiMap
;
import
com.google.common.collect.ImmutableBiMap
;
import
com.google.common.primitives.Bytes
;
import
java.nio.charset.Charset
;
import
java.util.Arrays
;
public
class
UriRecord
implements
ParsedNdefRecord
{
private
static
final
String
TAG
=
"UriRecord"
;
public
static
final
String
RECORD_TYPE
=
"UriRecord"
;
private
static
final
BiMap
<
Byte
,
String
>
URI_PREFIX_MAP
=
ImmutableBiMap
.<
Byte
,
String
>
builder
()
.
put
((
byte
)
0x00
,
""
)
.
put
((
byte
)
0x01
,
"http://www."
)
.
put
((
byte
)
0x02
,
"https://www."
)
.
put
((
byte
)
0x03
,
"http://"
)
.
put
((
byte
)
0x04
,
"https://"
)
.
put
((
byte
)
0x05
,
"tel:"
)
.
put
((
byte
)
0x06
,
"mailto:"
)
.
put
((
byte
)
0x07
,
"ftp://anonymous:anonymous@"
)
.
put
((
byte
)
0x08
,
"ftp://ftp."
)
.
put
((
byte
)
0x09
,
"ftps://"
)
.
put
((
byte
)
0x0A
,
"sftp://"
)
.
put
((
byte
)
0x0B
,
"smb://"
)
.
put
((
byte
)
0x0C
,
"nfs://"
)
.
put
((
byte
)
0x0D
,
"ftp://"
)
.
put
((
byte
)
0x0E
,
"dav://"
)
.
put
((
byte
)
0x0F
,
"news:"
)
.
put
((
byte
)
0x10
,
"telnet://"
)
.
put
((
byte
)
0x11
,
"imap:"
)
.
put
((
byte
)
0x12
,
"rtsp://"
)
.
put
((
byte
)
0x13
,
"urn:"
)
.
put
((
byte
)
0x14
,
"pop:"
)
.
put
((
byte
)
0x15
,
"sip:"
)
.
put
((
byte
)
0x16
,
"sips:"
)
.
put
((
byte
)
0x17
,
"tftp:"
)
.
put
((
byte
)
0x18
,
"btspp://"
)
.
put
((
byte
)
0x19
,
"btl2cap://"
)
.
put
((
byte
)
0x1A
,
"btgoep://"
)
.
put
((
byte
)
0x1B
,
"tcpobex://"
)
.
put
((
byte
)
0x1C
,
"irdaobex://"
)
.
put
((
byte
)
0x1D
,
"file://"
)
.
put
((
byte
)
0x1E
,
"urn:epc:id:"
)
.
put
((
byte
)
0x1F
,
"urn:epc:tag:"
)
.
put
((
byte
)
0x20
,
"urn:epc:pat:"
)
.
put
((
byte
)
0x21
,
"urn:epc:raw:"
)
.
put
((
byte
)
0x22
,
"urn:epc:"
)
.
put
((
byte
)
0x23
,
"urn:nfc:"
)
.
build
();
private
final
Uri
mUri
;
@SuppressLint
(
"RestrictedApi"
)
public
UriRecord
(
Uri
uri
)
{
this
.
mUri
=
Preconditions
.
checkNotNull
(
uri
);
}
@Override
public
String
str
()
{
return
mUri
.
toString
();
}
public
static
UriRecord
parse
(
NdefRecord
record
)
{
short
tnf
=
record
.
getTnf
();
if
(
tnf
==
NdefRecord
.
TNF_WELL_KNOWN
)
{
return
parseWellKnown
(
record
);
}
else
if
(
tnf
==
NdefRecord
.
TNF_ABSOLUTE_URI
)
{
return
parseAbsolute
(
record
);
}
throw
new
IllegalArgumentException
(
"Unknown TNF "
+
tnf
);
}
/** Parse and absolute URI record */
private
static
UriRecord
parseAbsolute
(
NdefRecord
record
)
{
byte
[]
payload
=
record
.
getPayload
();
Uri
uri
=
Uri
.
parse
(
new
String
(
payload
,
Charset
.
forName
(
"UTF-8"
)));
return
new
UriRecord
(
uri
);
}
/** Parse an well known URI record */
@SuppressLint
(
"RestrictedApi"
)
private
static
UriRecord
parseWellKnown
(
NdefRecord
record
)
{
Preconditions
.
checkArgument
(
Arrays
.
equals
(
record
.
getType
(),
NdefRecord
.
RTD_URI
));
byte
[]
payload
=
record
.
getPayload
();
/*
* payload[0] contains the URI Identifier Code, per the
* NFC Forum "URI Record Type Definition" section 3.2.2.
*
* payload[1]...payload[payload.length - 1] contains the rest of
* the URI.
*/
String
prefix
=
URI_PREFIX_MAP
.
get
(
payload
[
0
]);
byte
[]
fullUri
=
Bytes
.
concat
(
prefix
.
getBytes
(
Charset
.
forName
(
"UTF-8"
)),
Arrays
.
copyOfRange
(
payload
,
1
,
payload
.
length
));
Uri
uri
=
Uri
.
parse
(
new
String
(
fullUri
,
Charset
.
forName
(
"UTF-8"
)));
return
new
UriRecord
(
uri
);
}
public
static
boolean
isUri
(
NdefRecord
record
)
{
try
{
parse
(
record
);
return
true
;
}
catch
(
IllegalArgumentException
e
)
{
return
false
;
}
}
private
static
final
byte
[]
EMPTY
=
new
byte
[
0
];
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment