From 41681e0be1d6ba0005f8c6174e2335e647a0fa22 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Mon, 4 Oct 2010 09:34:39 -0700 Subject: [PATCH 1/6] new SaveTag activity, additional utilities The SaveTag activity will receive an intent with the contents of the NdefRecord, and will be responsible for commiting that record to the database. Add NdefUtil, which can convert an NdefRecord to a URI, and vise-versa. Change-Id: Icf8682a00774da6e246961d34de5bc5baa7550cb --- apps/Tag/Android.mk | 3 +- apps/Tag/AndroidManifest.xml | 1 + .../src/com/android/apps/tag/NdefUtil.java | 150 ++++++++++++++++++ .../Tag/src/com/android/apps/tag/SaveTag.java | 52 ++++++ .../src/com/android/apps/tag/TagDBHelper.java | 56 +++++-- .../Tag/src/com/android/apps/tag/TagList.java | 23 ++- apps/Tag/src/com/android/apps/tag/TagUi.java | 26 --- apps/Tag/src/com/android/apps/tag/Tags.java | 4 + .../apps/tag/TagBroadcastReceiverTest.java | 44 ----- 9 files changed, 269 insertions(+), 90 deletions(-) create mode 100644 apps/Tag/src/com/android/apps/tag/NdefUtil.java create mode 100644 apps/Tag/src/com/android/apps/tag/SaveTag.java delete mode 100644 apps/Tag/src/com/android/apps/tag/TagUi.java delete mode 100644 apps/Tag/tests/src/com/android/apps/tag/TagBroadcastReceiverTest.java diff --git a/apps/Tag/Android.mk b/apps/Tag/Android.mk index 949cd3f6b..f069cd859 100644 --- a/apps/Tag/Android.mk +++ b/apps/Tag/Android.mk @@ -3,11 +3,12 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional +LOCAL_STATIC_JAVA_LIBRARIES := guava + # Only compile source java files in this apk. LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := TagApp -# LOCAL_PROGUARD_EABLED := disabled # LOCAL_SDK_VERSION := current diff --git a/apps/Tag/AndroidManifest.xml b/apps/Tag/AndroidManifest.xml index 3388a3031..13fedddd8 100644 --- a/apps/Tag/AndroidManifest.xml +++ b/apps/Tag/AndroidManifest.xml @@ -31,6 +31,7 @@ + diff --git a/apps/Tag/src/com/android/apps/tag/NdefUtil.java b/apps/Tag/src/com/android/apps/tag/NdefUtil.java new file mode 100644 index 000000000..f2b01bbbe --- /dev/null +++ b/apps/Tag/src/com/android/apps/tag/NdefUtil.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.apps.tag; + +import com.google.common.base.Preconditions; +import com.google.common.collect.BiMap; +import com.google.common.collect.ImmutableBiMap; +import com.google.common.primitives.Bytes; +import com.trustedlogic.trustednfc.android.NdefRecord; + +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.Charsets; +import java.util.Arrays; + +/** + * Utilities for dealing with conversions to and from NdefRecords. + * + * TODO: Possibly move this class into core Android. + */ +public class NdefUtil { + private static final byte[] EMPTY = new byte[0]; + + /** + * NFC Forum "URI Record Type Definition" + * + * This is a mapping of "URI Identifier Codes" to URI string prefixes, + * per section 3.2.2 of the NFC Forum URI Record Type Definition document. + */ + private static final + BiMap URI_PREFIX_MAP = ImmutableBiMap.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(); + + /** + * Create a new {@link NdefRecord} containing the supplied {@link URI}. + */ + public static NdefRecord toUriRecord(URI uri) { + byte[] uriBytes = uri.toString().getBytes(Charsets.UTF_8); + + /* + * We prepend 0x00 to the bytes of the URI to indicate that this + * is the entire URI, and we are not taking advantage of the + * URI shortening rules in the NFC Forum URI spec section 3.2.2. + * This produces a NdefRecord which is slightly larger than + * necessary. + * + * In the future, we should use the URI shortening rules in 3.2.2 + * to create a smaller NdefRecord. + */ + byte[] payload = Bytes.concat(new byte[] { 0x00 }, uriBytes); + + return new NdefRecord(NdefRecord.TNF_WELL_KNOWN_TYPE, + NdefRecord.TYPE_URI, EMPTY, payload); + } + + /** + * Convert {@link NdefRecord} into a {@link URI}. + * + * TODO: This class does not handle NdefRecords where the TNF + * (Type Name Format) of the class is {@link NdefRecord#TNF_ABSOLUTE_URI}. + * This should be fixed. + * + * @throws URISyntaxException if the {@code NdefRecord} contains an + * invalid URI. + * @throws IllegalArgumentException if the NdefRecord is not a + * record containing a URI. + */ + public static URI toURI(NdefRecord record) throws URISyntaxException { + Preconditions.checkArgument(record.getTnf() == NdefRecord.TNF_WELL_KNOWN_TYPE); + Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.TYPE_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(Charsets.UTF_8), + Arrays.copyOfRange(payload, 1, payload.length - 1)); + + return new URI(new String(fullUri, Charsets.UTF_8)); + } + + public static boolean isURI(NdefRecord record) { + try { + toURI(record); + return true; + } catch (IllegalArgumentException e) { + return false; + } catch (URISyntaxException e) { + return false; + } + } +} diff --git a/apps/Tag/src/com/android/apps/tag/SaveTag.java b/apps/Tag/src/com/android/apps/tag/SaveTag.java new file mode 100644 index 000000000..877f9a711 --- /dev/null +++ b/apps/Tag/src/com/android/apps/tag/SaveTag.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.apps.tag; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.widget.Toast; + +/** + * @author nnk@google.com (Nick Kralevich) + */ +public class SaveTag extends Activity implements DialogInterface.OnClickListener { + + @Override + protected void onStart() { + super.onStart(); + showDialog(1); + String s = getIntent().getExtras().toString(); + Toast.makeText(this.getBaseContext(), "SaveTag: " + s, Toast.LENGTH_SHORT).show(); + } + + @Override + protected Dialog onCreateDialog(int id, Bundle args) { + return new AlertDialog.Builder(this) + .setTitle("Welcome! T2000 Festival") + .setPositiveButton("Save", this) + .setNegativeButton("Cancel", this) + .create(); + } + + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } +} diff --git a/apps/Tag/src/com/android/apps/tag/TagDBHelper.java b/apps/Tag/src/com/android/apps/tag/TagDBHelper.java index 15c18f3ba..a105d5c78 100644 --- a/apps/Tag/src/com/android/apps/tag/TagDBHelper.java +++ b/apps/Tag/src/com/android/apps/tag/TagDBHelper.java @@ -19,6 +19,13 @@ package com.android.apps.tag; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteStatement; +import com.google.common.annotations.VisibleForTesting; +import com.trustedlogic.trustednfc.android.NdefMessage; +import com.trustedlogic.trustednfc.android.NdefRecord; + +import java.net.URI; +import java.util.Date; /** * @author nnk@google.com (Nick Kralevich) @@ -26,28 +33,51 @@ import android.database.sqlite.SQLiteOpenHelper; public class TagDBHelper extends SQLiteOpenHelper { private static final int DATABASE_VERSION = 1; - private static final String TABLE_CREATE = "create table Tags (" - + "_id INTEGER PRIMARY KEY ASC, " - + "description TEXT, " - + "date TEXT" + + private static final String NDEF_MSG = "create table NdefMessage (" + + "_id INTEGER NOT NULL, " + + "bytes TEXT NOT NULL, " // TODO: This should be a blob + + "date TEXT NOT NULL, " + + "PRIMARY KEY(_id)" + ")"; - private static final String FAKE_DATA = - "INSERT INTO Tags (description) values ('hello world')"; - - private static final String FAKE_DATA2 = - "INSERT INTO Tags (description) values ('hi world')"; + private static final String INSERT = + "INSERT INTO NdefMessage (bytes, date) values (?, ?)"; public TagDBHelper(Context context) { - super(context, "Tags.db", null, DATABASE_VERSION); + this(context, "Tags.db"); + } + + @VisibleForTesting + public TagDBHelper(Context context, String dbFile) { + super(context, dbFile, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { - db.execSQL(TABLE_CREATE); - db.execSQL(FAKE_DATA); - db.execSQL(FAKE_DATA2); + db.execSQL(NDEF_MSG); + + // A fake message containing 1 URL + NdefMessage msg1 = new NdefMessage(new NdefRecord[] { + NdefUtil.toUriRecord(URI.create("http://www.google.com")) + }); + + // A fake message containing 2 URLs + NdefMessage msg2 = new NdefMessage(new NdefRecord[] { + NdefUtil.toUriRecord(URI.create("http://www.youtube.com")), + NdefUtil.toUriRecord(URI.create("http://www.android.com")) + }); + + insert(db, msg1); + insert(db, msg2); + } + + private void insert(SQLiteDatabase db, NdefMessage msg) { + SQLiteStatement stmt = db.compileStatement(INSERT); + stmt.bindString(1, new String(msg.toByteArray())); // TODO: This should be a blob + stmt.bindString(2, new Date().toString()); + stmt.executeInsert(); } @Override diff --git a/apps/Tag/src/com/android/apps/tag/TagList.java b/apps/Tag/src/com/android/apps/tag/TagList.java index f8a93e692..daaa9c47e 100644 --- a/apps/Tag/src/com/android/apps/tag/TagList.java +++ b/apps/Tag/src/com/android/apps/tag/TagList.java @@ -34,24 +34,24 @@ import android.widget.Toast; */ public class TagList extends ListActivity implements DialogInterface.OnClickListener { + private SQLiteDatabase db; + private Cursor cursor; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Toast.makeText(getBaseContext(), "entered method", Toast.LENGTH_SHORT).show(); - SQLiteDatabase db = new TagDBHelper(this.getBaseContext()).getReadableDatabase(); - Cursor c = db.query("Tags", new String[] { "_id", "description" }, null, null, null, null, null); + db = new TagDBHelper(getBaseContext()).getReadableDatabase(); + cursor = db.query("NdefMessage", new String[] { "_id", "bytes" }, null, null, null, null, null); SimpleCursorAdapter sca = new SimpleCursorAdapter(this, android.R.layout.two_line_list_item, - c, - new String[] { "description" }, + cursor, + new String[] { "bytes" }, new int[] { android.R.id.text1 }); setListAdapter(sca); registerForContextMenu(getListView()); - c.close(); - db.close(); Toast.makeText(getBaseContext(), "exit method", Toast.LENGTH_SHORT).show(); } @@ -73,6 +73,17 @@ public class TagList extends ListActivity implements DialogInterface.OnClickList .create(); } + @Override + protected void onDestroy() { + if (cursor != null) { + cursor.close(); + } + if (db != null) { + db.close(); + } + super.onDestroy(); + } + @Override protected void onListItemClick(ListView l, View v, int position, long id) { showDialog(1); diff --git a/apps/Tag/src/com/android/apps/tag/TagUi.java b/apps/Tag/src/com/android/apps/tag/TagUi.java deleted file mode 100644 index 98f384244..000000000 --- a/apps/Tag/src/com/android/apps/tag/TagUi.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.apps.tag; - - -/** - * @author nnk@google.com (Nick Kralevich) - */ -public class TagUi { - - -} diff --git a/apps/Tag/src/com/android/apps/tag/Tags.java b/apps/Tag/src/com/android/apps/tag/Tags.java index 781e05e21..d9fa2e79e 100644 --- a/apps/Tag/src/com/android/apps/tag/Tags.java +++ b/apps/Tag/src/com/android/apps/tag/Tags.java @@ -32,6 +32,10 @@ public class Tags extends TabActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + // While we're doing development, delete the database every time we start. + getBaseContext().getDatabasePath("Tags.db").delete(); + setContentView(R.layout.main); Resources res = getResources(); diff --git a/apps/Tag/tests/src/com/android/apps/tag/TagBroadcastReceiverTest.java b/apps/Tag/tests/src/com/android/apps/tag/TagBroadcastReceiverTest.java deleted file mode 100644 index e030b6aae..000000000 --- a/apps/Tag/tests/src/com/android/apps/tag/TagBroadcastReceiverTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.apps.tag; - -import android.content.Intent; -import android.test.ActivityInstrumentationTestCase2; - -/** - * @author nnk@google.com (Nick Kralevich) - */ -public class TagBroadcastReceiverTest extends ActivityInstrumentationTestCase2 { - /** - * Creates an {@link ActivityInstrumentationTestCase2} for the {@link Tags} activity. - */ - public TagBroadcastReceiverTest() { - super(Tags.class); - } - - public void testWrongMessage() { - TagBroadcastReceiver receiver = new TagBroadcastReceiver(); - Intent i = new Intent().setAction("BOGUS"); - receiver.onReceive(getActivity().getBaseContext(), i); - assertDatabaseNoChange(receiver); - } - - private void assertDatabaseNoChange(TagBroadcastReceiver receiver) { - // TODO: implement - } - -} From afad3fa14a102e1d38bbdcfc7d6dc70243f23ce7 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Tue, 5 Oct 2010 12:44:50 -0700 Subject: [PATCH 2/6] new icon. Change-Id: I17751bbd0dc9d900002ef68ee51a4ddaf1600281 --- apps/Tag/AndroidManifest.xml | 2 +- apps/Tag/res/drawable/ic_launcher_nfc.png | Bin 0 -> 4865 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 apps/Tag/res/drawable/ic_launcher_nfc.png diff --git a/apps/Tag/AndroidManifest.xml b/apps/Tag/AndroidManifest.xml index 13fedddd8..adb937349 100644 --- a/apps/Tag/AndroidManifest.xml +++ b/apps/Tag/AndroidManifest.xml @@ -22,7 +22,7 @@ - + diff --git a/apps/Tag/res/drawable/ic_launcher_nfc.png b/apps/Tag/res/drawable/ic_launcher_nfc.png new file mode 100644 index 0000000000000000000000000000000000000000..9b076abf253b94fa91924fb098608f55866ece61 GIT binary patch literal 4865 zcmV+c6aMUpP)#^^z?n-o%j8^dmIq~nU)!o`KrG9`})8C{hsf6&#(Vq5|76*-oCj>#~~O8 zXdIyLvdJ&!q{D{~z~>WHQ;%>)P5{WM*a}7Q66*OQllLT`m{8y1Ebu1Y}82RMhik z&YanF|NZyhR8&+{@ci@7|7qK{Z9C~V-SnN0fl{m0k@E6#aV_?|e7%c#V7}go6DQ#D zc%ac}t{gza8w;G9n~P{P`gNU=NQ97lbi3W??(W9Gz<@j)4l9yuF)m)bc>aC&-FM6K z<;&+22x1mXmo8m!@ZiCt>(;G%WAo5b%?~{Az^$`p&1y)U&+5YGavwe(w}}%c))GLE zJ^b*)t2b=eu;t~KU*6K!*Y^dD>uzgn3(_^h3{*iu!Pgj-jv!c`4scR*W?+~tJv}`P zj3Nn)o>sYj&6+jK@4ffln`pu{DNs_N@@uo%jE_J5m~9T`&6`(NSXd~=Ofj>%y1M+S zr=EI%)Nv&->)jV#c;PJq=NMhbML_xKb)>YkG?oG?HU5Y}N)7UD`i>nthR&ZcV+Iy2 zT7(G`CLkjtLz)D|K)sZV>ar)Fd~!V*<=%L*5r|*u1VEfrC-&fj5B?_savk+0cinZ@ ztE5Iz{_fo0ry4DUg_!jpblsciS{2D_s#yk>g&2w@OO_xjD@(}9GG5MHM+}for%M5& zP6}B`0^Upp_K!S?)P%?|pSN>6e*Cy4J3ISkI=7GwHyPIE-Me>pU+g??4u`|};)^eC zZftD)DV@vgWJJ{D9Aw4C#n9{ZqXv*9XZVORi?@$})|w zSyxw^`TqNmjS4`?VwIS*Oe#UQ$$}oUV<`2J%cRKAD4|s;kg3xkCo_XSOI(t{3Pqyd zIbeqmAGXjT!rA>52Pj#jqDf0|s%H@Q{qsBMcgK+uMotHFxIOoYM_q#G)hEf5IAM$HDLb~vRpwP;KNkJJEFo`HZ#07Tq^KN^LX z02l~FaMB&Y{$3|=zyyP`6&1N^G}RlixUmKkD+-}fDi8>TY0P-qY|xm9gZwn9`m%hy z`snrW1mn;s<=`zYFM(ol`(bm3&|~wV+v-Cv9ee5MBgP!D2XJJU2^)8JVp>HeZk%0@ zg)?fPQL6+{>DaLuGl8N%5I}973No@gDZwNXC8?WEs2uNcF);>RL3G;!IB;?h`%hW% zMUNA1e;9lFeAxfTgP8X5aooLh8s<%{20Lh0z0`){_Y$Dtaga9mvGl8ZspYZNFj zXi#3DM}28Ns*19S6<1Xu(VcfCr9zr4N<%V(D0*{yBZd0dLVNC3ZjbsrvF?!qk# z8W4Sp-y!)F?|&5a0zFD+_Mso1Ed z8Yv31$7!f8#^2sCA3ctU2oTv8`9m>cQ~)+l5dC&P9KJ9H!eR9H2C%2&B#a-nVd3OL z+`3>ADkvrjgd&1XaBpC;2CEUv9Jr>&fZwi~g2y)!NGQbm4?B>Tsln2wdSYDUqI(q#P)SL#cGPmQ z;a)6E%owye&O>!hIb_J8*r=#F1B)l-z(K+7!44ZX?d!&8XOwW#x$AfK;?t96Jh);O z>L{l21;Q}fT;%Nx_|3{G`0Lk?z!fuM-FshY!C;cHzX7e?GqYGZY{(Py?G;&)+wjUNAU$8(F@bOsxOl6yDt52Ul2$C*Eqo-^62>Gr2-A zY0&P*_0tRS1*Iu(em00heSU1--G(>iq$<=@mcvj`hKQ~NXM#D{^tl(meDzcO`sJPYqN5)w%JOBTCq8oF0~R}ea!m;y zxULckg%VyxKGtq-9b%e47=lhI!JYHUM3ulA(PHzy({z4(sAzY-J|_xXUr%?`QBiZJXi$BdtBH>-mA6C0SCGK-Mtou*G>@tgo#aqR;K{T zO@M9qpFVW?wRmy+F+4)iG(}Z(t`GAju%pd}8)n&1CSs}R*kjOeFXr+xZ`3ww@rLn-G!iAE8pbmqoJBb2fj>=89~eBJ}OBnt-WW-3nsjl#~;MB@+{QlD8k&9cZ3a10Q)Ux6hBIQwy;5s0F5|4%?3oVD98%aXpT-8!HXSK469=s==qH zt(bdN@pn?+PK%21N@+A&WRb^G<(5O8R{>d01?-AK9Cc;l_qzx2$c9hw?%p;iXxUl) zm`&1XfK;v)1zHKD8M)ZFw}-rzTc}!qK+4xCFt=KtV9{V0r~2%|pmPLWl%+y#o`PZ^ z`p)Esoea2in3|<)D=IAj@rqU$4Ost+`S|_MuEvI+UyXlUGaWx$QirKEMrg8&V3ikQ z-G^QH!}~4dkz$mmNnm&TP(ln_)l?wf_Xbqhdgv@MGEoT#(ztVKvnY;=5i`{|blN8B z-{RHSMUxvLeRV9rZkhCL2X{A`a2)XEpbAm*hkGJ;siqb0^bgpI3DAyxT6Gv38#b=aG@MM`0T<@A#sD&&Zg)=0B*%=V- zK0=Xbc7_tUT2?v<20T%OlXv>0Q^nE}N%M+YDHd6`|}5RO=6@M%jC)|bJdD#fg^cpFyDv+a_Y-+D72D9CZJcCYv#KEC7=7BFNgWVez6#=eRa^YX6 zk_cwnd=W}Fk^s=rppgl$7>r6N#)^uZZTJm!W5NcBjYGd5*OaT!T(8ETl}Pc+=3l|(i6qSr1i=~ z63iswdJ>X5`B`L#`1?R40nk`tP<%K@Jn`WrSFKWx;*2OxSf%jAWTMc{Hia1>iANJ2 zhdfg>c|#35WEJ^-jhxj*3Y#Z1%w5N!mM7|B!Du4x(kOYXs8B<}G_cqEMquKj!65$c zON49D=QD`>&Pgor_(RaEl`!bk32-tEss(mCqR?8f)dDV-|0+hVThPP#-qrsr4&1O4eGMRivqfvXV z+VKQ$TSOl0xSf*Dyo4H&tYNZIbEcHzRNEHq1(H8(sri{HivWQv(&#df)sIg_YDlK zbZSe6V;j?;HK|sKno_E{JYJE`q{c~|6DEV*H((jMgPM>05QF{u_qV?N_S?_0rYB{+ z@(kj|b-7$e*REZA--;D09-2RY{txo<@-lfpYBc`T$v5Kl^z`)a*|X;ZBKGrMueXh5 z9Ep)0X(Y}5)=f5~^|jYtdx(UZs?+JJxI}cN0V4MBy|Qkr)!I%BI>~Y&@sN}eJsjn- z02=lfig;20wz2_pqREopQF4U|6i?ckSW>3QaOPamr@!#SO!y|*bJQ(_G2Hn1L6^nM n@rS&9$En6RK>yF%{|YbwdN6dZ4N$*f00000NkvXXu0mjf9DhTp literal 0 HcmV?d00001 From 97d3699cd92e2c15623935d723f1b85ec673b73a Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Tue, 5 Oct 2010 15:26:04 -0700 Subject: [PATCH 3/6] Have TagBroadcastReceiver start the SaveTag activity. Change-Id: I6dc8757ca7eec87efe622b0b2688dd29c5883185 --- .../apps/tag/TagBroadcastReceiver.java | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/apps/Tag/src/com/android/apps/tag/TagBroadcastReceiver.java b/apps/Tag/src/com/android/apps/tag/TagBroadcastReceiver.java index 015e897ad..d576bdb19 100644 --- a/apps/Tag/src/com/android/apps/tag/TagBroadcastReceiver.java +++ b/apps/Tag/src/com/android/apps/tag/TagBroadcastReceiver.java @@ -19,14 +19,12 @@ package com.android.apps.tag; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.widget.Toast; import com.trustedlogic.trustednfc.android.NdefMessage; -import com.trustedlogic.trustednfc.android.NdefRecord; import com.trustedlogic.trustednfc.android.NfcManager; /** - * This class doesn't work. Sorry. Think of this class as pseudo - * code for now. + * When we receive a new NDEF tag, start the activity to + * process the tag. */ public class TagBroadcastReceiver extends BroadcastReceiver { @@ -34,19 +32,10 @@ public class TagBroadcastReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(NfcManager.NDEF_TAG_DISCOVERED_ACTION)) { NdefMessage msg = intent.getParcelableExtra(NfcManager.NDEF_MESSAGE_EXTRA); - Toast.makeText(context, "got a new message", Toast.LENGTH_SHORT).show(); - insertIntoDb(msg); + Intent i = new Intent(context, SaveTag.class) + .putExtra(NfcManager.NDEF_MESSAGE_EXTRA, msg) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(i); } } - - private void insertIntoDb(NdefMessage msg) { - for (NdefRecord record : msg.getRecords()) { - insertIntoRecordDb(record.getType(), record.getPayload()); - } - } - - private void insertIntoRecordDb(byte[] type, byte[] payload) { - // do something... - } - } From 640764400347b35baa20089961560291b36e5840 Mon Sep 17 00:00:00 2001 From: Anatol Pomazau Date: Tue, 5 Oct 2010 16:32:43 -0700 Subject: [PATCH 4/6] Dismiss "Save" dialog on activity stop Change-Id: I0e63b679c9677e50f7b5b6a20c9eb840f983aa18 --- apps/Tag/src/com/android/apps/tag/SaveTag.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/Tag/src/com/android/apps/tag/SaveTag.java b/apps/Tag/src/com/android/apps/tag/SaveTag.java index 877f9a711..5c75a707f 100644 --- a/apps/Tag/src/com/android/apps/tag/SaveTag.java +++ b/apps/Tag/src/com/android/apps/tag/SaveTag.java @@ -49,4 +49,9 @@ public class SaveTag extends Activity implements DialogInterface.OnClickListener public void onClick(DialogInterface dialog, int which) { finish(); } + + protected void onStop() { + super.onStop(); + dismissDialog(1); + } } From ce6bbfae018b5629fd86c77b81fc4d8c655fa275 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Tue, 5 Oct 2010 16:28:46 -0700 Subject: [PATCH 5/6] More data for testing. I managed to extract data from a real NFC tag. Make that data available for unittests / other testing. Change-Id: I99cd8d6a32dc20fd7e33191f86def71236474d9a --- .../Tag/src/com/android/apps/tag/SaveTag.java | 19 +++++- .../src/com/android/apps/tag/TagDBHelper.java | 59 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/apps/Tag/src/com/android/apps/tag/SaveTag.java b/apps/Tag/src/com/android/apps/tag/SaveTag.java index 5c75a707f..2be12881a 100644 --- a/apps/Tag/src/com/android/apps/tag/SaveTag.java +++ b/apps/Tag/src/com/android/apps/tag/SaveTag.java @@ -21,7 +21,11 @@ import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; +import android.util.Log; import android.widget.Toast; +import com.trustedlogic.trustednfc.android.NfcManager; +import com.trustedlogic.trustednfc.android.NdefMessage; + /** * @author nnk@google.com (Nick Kralevich) @@ -32,7 +36,10 @@ public class SaveTag extends Activity implements DialogInterface.OnClickListener protected void onStart() { super.onStart(); showDialog(1); - String s = getIntent().getExtras().toString(); + NdefMessage msg = getIntent().getParcelableExtra(NfcManager.NDEF_MESSAGE_EXTRA); + + String s = toHexString(msg.toByteArray()); + Log.d("SaveTag", s); Toast.makeText(this.getBaseContext(), "SaveTag: " + s, Toast.LENGTH_SHORT).show(); } @@ -54,4 +61,14 @@ public class SaveTag extends Activity implements DialogInterface.OnClickListener super.onStop(); dismissDialog(1); } + + private static final char[] hexDigits = "0123456789abcdef".toCharArray(); + + private static String toHexString(byte[] bytes) { + StringBuilder sb = new StringBuilder(3 * bytes.length); + for (byte b : bytes) { + sb.append("(byte) 0x").append(hexDigits[(b >> 4) & 0xf]).append(hexDigits[b & 0xf]).append(", "); + } + return sb.toString(); + } } diff --git a/apps/Tag/src/com/android/apps/tag/TagDBHelper.java b/apps/Tag/src/com/android/apps/tag/TagDBHelper.java index a105d5c78..36ae7a0c2 100644 --- a/apps/Tag/src/com/android/apps/tag/TagDBHelper.java +++ b/apps/Tag/src/com/android/apps/tag/TagDBHelper.java @@ -23,6 +23,7 @@ import android.database.sqlite.SQLiteStatement; import com.google.common.annotations.VisibleForTesting; import com.trustedlogic.trustednfc.android.NdefMessage; import com.trustedlogic.trustednfc.android.NdefRecord; +import com.trustedlogic.trustednfc.android.NfcException; import java.net.URI; import java.util.Date; @@ -44,6 +45,56 @@ public class TagDBHelper extends SQLiteOpenHelper { private static final String INSERT = "INSERT INTO NdefMessage (bytes, date) values (?, ?)"; + private static final byte[] REAL_NFC_MSG = new byte[] { + (byte) 0xd1, + (byte) 0x02, + (byte) 0x2b, + (byte) 0x53, + (byte) 0x70, + (byte) 0x91, + (byte) 0x01, + (byte) 0x17, + (byte) 0x54, + (byte) 0x02, + (byte) 0x65, + (byte) 0x6e, + (byte) 0x4e, + (byte) 0x46, + (byte) 0x43, + (byte) 0x20, + (byte) 0x46, + (byte) 0x6f, + (byte) 0x72, + (byte) 0x75, + (byte) 0x6d, + (byte) 0x20, + (byte) 0x54, + (byte) 0x79, + (byte) 0x70, + (byte) 0x65, + (byte) 0x20, + (byte) 0x34, + (byte) 0x20, + (byte) 0x54, + (byte) 0x61, + (byte) 0x67, + (byte) 0x51, + (byte) 0x01, + (byte) 0x0c, + (byte) 0x55, + (byte) 0x01, + (byte) 0x6e, + (byte) 0x78, + (byte) 0x70, + (byte) 0x2e, + (byte) 0x63, + (byte) 0x6f, + (byte) 0x6d, + (byte) 0x2f, + (byte) 0x6e, + (byte) 0x66, + (byte) 0x63 + }; public TagDBHelper(Context context) { this(context, "Tags.db"); @@ -71,6 +122,14 @@ public class TagDBHelper extends SQLiteOpenHelper { insert(db, msg1); insert(db, msg2); + + try { + // A real message obtained from an NFC Forum Type 4 tag. + NdefMessage msg3 = new NdefMessage(REAL_NFC_MSG); + insert(db, msg3); + } catch (NfcException e) { + throw new RuntimeException(e); + } } private void insert(SQLiteDatabase db, NdefMessage msg) { From 9f62c24a68e5408e5792fb185ab2e58d0c507265 Mon Sep 17 00:00:00 2001 From: Anatol Pomazau Date: Tue, 5 Oct 2010 17:39:05 -0700 Subject: [PATCH 6/6] Show 'Save tag' dialog even if the screen is turned off Change-Id: I7d8b2fa74525e81db1743bf3e4283778192fc047 --- apps/Tag/src/com/android/apps/tag/SaveTag.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/Tag/src/com/android/apps/tag/SaveTag.java b/apps/Tag/src/com/android/apps/tag/SaveTag.java index 2be12881a..ac0ebb5de 100644 --- a/apps/Tag/src/com/android/apps/tag/SaveTag.java +++ b/apps/Tag/src/com/android/apps/tag/SaveTag.java @@ -22,9 +22,10 @@ import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; import android.util.Log; +import android.view.WindowManager; import android.widget.Toast; -import com.trustedlogic.trustednfc.android.NfcManager; import com.trustedlogic.trustednfc.android.NdefMessage; +import com.trustedlogic.trustednfc.android.NfcManager; /** @@ -35,6 +36,15 @@ public class SaveTag extends Activity implements DialogInterface.OnClickListener @Override protected void onStart() { super.onStart(); + + getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED + | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD + | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON + | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON + | WindowManager.LayoutParams.FLAG_DIM_BEHIND + ); + showDialog(1); NdefMessage msg = getIntent().getParcelableExtra(NfcManager.NDEF_MESSAGE_EXTRA); @@ -57,6 +67,7 @@ public class SaveTag extends Activity implements DialogInterface.OnClickListener finish(); } + @Override protected void onStop() { super.onStop(); dismissDialog(1);