TextRecord.java revision 24147eeedccccc552ba116c74384a8ea22da9dcb
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.apps.tag.record;
18
19import com.android.apps.tag.R;
20import com.google.common.annotations.VisibleForTesting;
21import com.google.common.base.Preconditions;
22import com.google.common.primitives.Bytes;
23
24import android.app.Activity;
25import android.nfc.NdefRecord;
26import android.view.LayoutInflater;
27import android.view.View;
28import android.view.ViewGroup;
29import android.widget.TextView;
30
31import java.io.UnsupportedEncodingException;
32import java.nio.charset.Charset;
33import java.nio.charset.Charsets;
34import java.util.Arrays;
35import java.util.Locale;
36
37/**
38 * An NFC Text Record
39 */
40public class TextRecord implements ParsedNdefRecord {
41
42    /** ISO/IANA language code */
43    private final String mLanguageCode;
44    private final String mText;
45
46    private TextRecord(String languageCode, String text) {
47        mLanguageCode = Preconditions.checkNotNull(languageCode);
48        mText = Preconditions.checkNotNull(text);
49    }
50
51    @Override
52    public View getView(Activity activity, LayoutInflater inflater, ViewGroup parent) {
53        TextView text = (TextView) inflater.inflate(R.layout.tag_text, parent, false);
54        text.setText(mText);
55        return text;
56    }
57
58    public String getText() {
59        return mText;
60    }
61
62    /**
63     * Returns the ISO/IANA language code associated with this text element.
64     *
65     * TODO: this should return a {@link java.util.Locale}
66     */
67    @VisibleForTesting
68    public String getLanguageCode() {
69        return mLanguageCode;
70    }
71
72    // TODO: deal with text fields which span multiple NdefRecords
73    public static TextRecord parse(NdefRecord record) {
74        Preconditions.checkArgument(record.getTnf() == NdefRecord.TNF_WELL_KNOWN);
75        Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.RTD_TEXT));
76        try {
77
78            byte[] payload = record.getPayload();
79
80            /*
81             * payload[0] contains the "Status Byte Encodings" field, per
82             * the NFC Forum "Text Record Type Definition" section 3.2.1.
83             *
84             * bit7 is the Text Encoding Field.
85             *
86             * if (Bit_7 == 0): The text is encoded in UTF-8
87             * if (Bit_7 == 1): The text is encoded in UTF16
88             *
89             * Bit_6 is reserved for future use and must be set to zero.
90             *
91             * Bits 5 to 0 are the length of the IANA language code.
92             */
93
94            String textEncoding = ((payload[0] & 0200) == 0) ? "UTF-8" : "UTF-16";
95            int languageCodeLength = payload[0] & 0077;
96
97            String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
98            String text = new String(payload,
99                    languageCodeLength + 1,
100                    payload.length - languageCodeLength - 1,
101                    textEncoding);
102            return new TextRecord(languageCode, text);
103
104        } catch (UnsupportedEncodingException e) {
105            // should never happen unless we get a malformed tag.
106            throw new IllegalArgumentException(e);
107        }
108    }
109
110    public static boolean isText(NdefRecord record) {
111        try {
112            parse(record);
113            return true;
114        } catch (IllegalArgumentException e) {
115            return false;
116        }
117    }
118
119    @VisibleForTesting
120    public static NdefRecord newTextRecord(String text, Locale locale) {
121        return newTextRecord(text, locale, true);
122    }
123
124    public static NdefRecord newTextRecord(String text, Locale locale, boolean encodeInUtf8) {
125        Preconditions.checkNotNull(text);
126        Preconditions.checkNotNull(locale);
127
128        byte[] langBytes = locale.getLanguage().getBytes(Charsets.US_ASCII);
129
130        Charset utfEncoding = encodeInUtf8 ? Charsets.UTF_8 : Charset.forName("UTF-16");
131        byte[] textBytes = text.getBytes(utfEncoding);
132
133        int utfBit = encodeInUtf8 ? 0 : (1 << 7);
134        char status = (char) (utfBit + langBytes.length);
135
136        byte[] data = Bytes.concat(
137           new byte[] { (byte) status },
138           langBytes,
139           textBytes
140        );
141
142        return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], data);
143    }
144}
145