122c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton/* 222c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton * Copyright (C) 2010 The Android Open Source Project 322c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton * 422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton * Licensed under the Apache License, Version 2.0 (the "License"); 522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton * you may not use this file except in compliance with the License. 622c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton * You may obtain a copy of the License at 722c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton * 822c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton * http://www.apache.org/licenses/LICENSE-2.0 922c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton * 1022c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton * Unless required by applicable law or agreed to in writing, software 1122c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton * distributed under the License is distributed on an "AS IS" BASIS, 1222c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1322c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton * See the License for the specific language governing permissions and 1422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton * limitations under the License 1522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton */ 1622c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 1722c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonpackage com.android.apps.tagcanon; 1822c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 1922c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport com.android.apps.tag.MockNdefMessages; 2022c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport com.google.common.base.Preconditions; 2122c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport com.google.common.primitives.Bytes; 2222c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 2322c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport android.app.ListActivity; 2422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport android.content.Intent; 2522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport android.content.res.Resources; 2622c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport android.graphics.Bitmap; 2722c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport android.graphics.drawable.BitmapDrawable; 2822c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport android.graphics.drawable.Drawable; 2922c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport android.nfc.NdefMessage; 3022c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport android.nfc.NdefRecord; 3122c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport android.nfc.NfcAdapter; 3222c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport android.os.Bundle; 3322c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport android.view.View; 3422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport android.widget.ArrayAdapter; 3522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport android.widget.ListView; 3622c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 3722c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport java.io.ByteArrayOutputStream; 3822c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport java.io.IOException; 3922c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport java.nio.charset.Charset; 405b1190b3e619b42da5696025da85f40512a84dc2Elliott Hughesimport java.nio.charset.StandardCharsets; 4122c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonimport java.util.Locale; 4222c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 4322c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton/** 4422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton * A test activity that launches tags as if they had been scanned. 4522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton */ 4622c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamiltonpublic class TagCanon extends ListActivity { 4722c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton static final String TAG = "TagCanon"; 4822c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton static final byte[] UID = new byte[] { 0x05, 0x00, 0x03, 0x08 }; 4922c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 5022c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton ArrayAdapter<TagDescription> mAdapter; 5122c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 5222c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton public static NdefRecord newTextRecord(String text, Locale locale, boolean encodeInUtf8) { 5322c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton Preconditions.checkNotNull(text); 5422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton Preconditions.checkNotNull(locale); 5522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 565b1190b3e619b42da5696025da85f40512a84dc2Elliott Hughes byte[] langBytes = locale.getLanguage().getBytes(StandardCharsets.US_ASCII); 5722c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 585b1190b3e619b42da5696025da85f40512a84dc2Elliott Hughes Charset utfEncoding = encodeInUtf8 ? StandardCharsets.UTF_8 : StandardCharsets.UTF_16; 5922c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton byte[] textBytes = text.getBytes(utfEncoding); 6022c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 6122c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton int utfBit = encodeInUtf8 ? 0 : (1 << 7); 6222c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton char status = (char) (utfBit + langBytes.length); 6322c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 6422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton byte[] data = Bytes.concat( 6522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton new byte[] { (byte) status }, 6622c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton langBytes, 6722c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton textBytes 6822c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton ); 6922c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 7022c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], data); 7122c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton } 7222c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 7322c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton public static NdefRecord newMimeRecord(String type, byte[] data) { 7422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton Preconditions.checkNotNull(type); 7522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton Preconditions.checkNotNull(data); 7622c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 775b1190b3e619b42da5696025da85f40512a84dc2Elliott Hughes byte[] typeBytes = type.getBytes(StandardCharsets.US_ASCII); 7822c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 7922c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton return new NdefRecord(NdefRecord.TNF_MIME_MEDIA, typeBytes, new byte[0], data); 8022c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton } 8122c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 8222c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton final NdefMessage[] buildImageMessages() { 8322c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton Resources res = getResources(); 8422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton Drawable drawable = res.getDrawable(R.drawable.ic_launcher_nfc); 8522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton Bitmap photo = ((BitmapDrawable) drawable).getBitmap(); 8622c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton final int size = photo.getWidth() * photo.getHeight() * 4; 8722c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton final ByteArrayOutputStream out = new ByteArrayOutputStream(size); 8822c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 8922c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton try { 9022c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton photo.compress(Bitmap.CompressFormat.PNG, 100, out); 9122c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton out.flush(); 9222c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton byte[] payload = out.toByteArray(); 9322c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton out.close(); 9422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 9522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton NdefRecord text = newTextRecord("There's an image below this text!", Locale.US, true); 9622c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton NdefRecord image = newMimeRecord("image/png", payload); 9722c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton NdefMessage[] msgs = new NdefMessage[] { 9822c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton new NdefMessage(new NdefRecord[] { text, image }) }; 9922c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 10022c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton return msgs; 10122c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton } catch (IOException e) { 10222c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton throw new RuntimeException("Failed to compress image", e); 10322c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton } 10422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton } 10522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 10622c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton static final class TagDescription { 10722c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton public String title; 1088714f956f029bdf2071d57077fab036076a99a1cJeff Hamilton NdefMessage[] msgs; 10922c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 11022c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton public TagDescription(String title, byte[] bytes) { 11122c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton this.title = title; 11222c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton try { 1138714f956f029bdf2071d57077fab036076a99a1cJeff Hamilton msgs = new NdefMessage[] { new NdefMessage(bytes) }; 11422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton } catch (Exception e) { 11522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton throw new RuntimeException("Failed to create tag description", e); 11622c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton } 11722c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton } 11822c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 11922c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton public TagDescription(String title, NdefMessage[] msgs) { 12022c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton this.title = title; 1218714f956f029bdf2071d57077fab036076a99a1cJeff Hamilton this.msgs = msgs; 12222c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton } 12322c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 12422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton @Override 12522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton public String toString() { 12622c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton return title; 12722c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton } 12822c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton } 12922c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 13022c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton @Override 13122c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton public void onCreate(Bundle savedState) { 13222c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton super.onCreate(savedState); 13322c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton ArrayAdapter<TagDescription> adapter = new ArrayAdapter<TagDescription>(this, 13422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton android.R.layout.simple_list_item_1, android.R.id.text1); 13522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton adapter.add(new TagDescription("Image", buildImageMessages())); 13622c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton adapter.add(new TagDescription("Real NFC message", MockNdefMessages.REAL_NFC_MSG)); 13722c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton adapter.add(new TagDescription("Call Google", MockNdefMessages.CALL_GOOGLE)); 13822c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton adapter.add(new TagDescription("English text", MockNdefMessages.ENGLISH_PLAIN_TEXT)); 13922c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton adapter.add(new TagDescription("Send text message", MockNdefMessages.SEND_TEXT_MESSAGE)); 14022c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton adapter.add(new TagDescription("SmartPoster URL & text", MockNdefMessages.SMART_POSTER_URL_AND_TEXT)); 14122c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton adapter.add(new TagDescription("SmartPoster URL", MockNdefMessages.SMART_POSTER_URL_NO_TEXT)); 14222c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton adapter.add(new TagDescription("VCARD", MockNdefMessages.VCARD)); 14322c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton adapter.add(new TagDescription("URI", MockNdefMessages.URI)); 14422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton setListAdapter(adapter); 14522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton mAdapter = adapter; 14622c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton } 14722c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton 14822c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton @Override 14922c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton public void onListItemClick(ListView l, View v, int position, long id) { 15022c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton TagDescription description = mAdapter.getItem(position); 151a29dc1ba19e86ae23f8789bbb8fce6b57130c561Jeff Hamilton Intent intent = new Intent(NfcAdapter.ACTION_TAG_DISCOVERED); 1528714f956f029bdf2071d57077fab036076a99a1cJeff Hamilton intent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, description.msgs); 15322c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton startActivity(intent); 15422c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton } 15522c803adaa028bbb7d8d1f9a1f4134de5b2f3c17Jeff Hamilton} 156