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