2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.apps.tag.record;
19 import com.android.apps.tag.R;
20 import com.android.apps.tag.record.UriRecord.UriRecordEditInfo;
21 import com.google.common.annotations.VisibleForTesting;
22 import com.google.common.base.Preconditions;
23 import com.google.common.primitives.Bytes;
25 import android.app.Activity;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.pm.PackageManager;
29 import android.content.pm.ResolveInfo;
30 import android.net.Uri;
31 import android.nfc.NdefRecord;
32 import android.os.Parcel;
33 import android.os.Parcelable;
34 import android.text.TextUtils;
35 import android.view.LayoutInflater;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.widget.ImageView;
39 import android.widget.TextView;
41 import java.io.UnsupportedEncodingException;
42 import java.nio.charset.Charset;
43 import java.util.Arrays;
44 import java.util.List;
45 import java.util.Locale;
50 public class TextRecord extends ParsedNdefRecord {
52 public static final String RECORD_TYPE = "TextRecord";
54 /** ISO/IANA language code */
55 private final String mLanguageCode;
56 private final String mText;
58 private TextRecord(String languageCode, String text) {
59 mLanguageCode = Preconditions.checkNotNull(languageCode);
60 mText = Preconditions.checkNotNull(text);
64 public View getView(Activity activity, LayoutInflater inflater, ViewGroup parent, int offset) {
65 TextView text = (TextView) inflater.inflate(R.layout.tag_text, parent, false);
71 public String getSnippet(Context context, Locale locale) {
75 public String getText() {
80 * Returns the ISO/IANA language code associated with this text element.
82 * TODO: this should return a {@link java.util.Locale}
85 public String getLanguageCode() {
90 public RecordEditInfo getEditInfo(Activity host) {
91 return new TextRecordEditInfo(mText);
95 * Returns a view in a list of record types for adding new records to a message.
97 public static View getAddView(Context context, LayoutInflater inflater, ViewGroup parent) {
98 ViewGroup root = (ViewGroup) inflater.inflate(
99 R.layout.tag_add_record_list_item, parent, false);
100 ((ImageView) root.findViewById(R.id.image)).setImageResource(R.drawable.ic_launcher_nfc);
101 ((TextView) root.findViewById(R.id.text)).setText(context.getString(R.string.tag_text));
103 root.setTag(new TextRecordEditInfo(""));
107 // TODO: deal with text fields which span multiple NdefRecords
108 public static TextRecord parse(NdefRecord record) {
109 Preconditions.checkArgument(record.getTnf() == NdefRecord.TNF_WELL_KNOWN);
110 Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.RTD_TEXT));
113 byte[] payload = record.getPayload();
114 Preconditions.checkArgument(payload.length > 0);
117 * payload[0] contains the "Status Byte Encodings" field, per
118 * the NFC Forum "Text Record Type Definition" section 3.2.1.
120 * bit7 is the Text Encoding Field.
122 * if (Bit_7 == 0): The text is encoded in UTF-8
123 * if (Bit_7 == 1): The text is encoded in UTF16
125 * Bit_6 is reserved for future use and must be set to zero.
127 * Bits 5 to 0 are the length of the IANA language code.
130 String textEncoding = ((payload[0] & 0200) == 0) ? "UTF-8" : "UTF-16";
131 int languageCodeLength = payload[0] & 0077;
132 Preconditions.checkArgument(payload.length - languageCodeLength - 1 >= 0);
134 String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
135 String text = new String(payload,
136 languageCodeLength + 1,
137 payload.length - languageCodeLength - 1,
139 return new TextRecord(languageCode, text);
141 } catch (UnsupportedEncodingException e) {
142 // should never happen unless we get a malformed tag.
143 throw new IllegalArgumentException(e);
147 public static boolean isText(NdefRecord record) {
151 } catch (IllegalArgumentException e) {
157 public static NdefRecord newTextRecord(String text, Locale locale) {
158 return newTextRecord(text, locale, true);
161 public static NdefRecord newTextRecord(String text, Locale locale, boolean encodeInUtf8) {
162 Preconditions.checkNotNull(text);
163 Preconditions.checkNotNull(locale);
165 byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
167 Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");
168 byte[] textBytes = text.getBytes(utfEncoding);
170 int utfBit = encodeInUtf8 ? 0 : (1 << 7);
171 char status = (char) (utfBit + langBytes.length);
173 byte[] data = Bytes.concat(
174 new byte[] { (byte) status },
179 return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], data);
182 public static class TextRecordEditInfo extends AbstractTextRecordEditInfo {
183 public TextRecordEditInfo(String text) {
187 public TextRecordEditInfo(Parcel in) {
192 public int getLayoutId() {
193 return R.layout.tag_edit_text;
197 public NdefRecord getValue() {
198 String text = getCurrentText();
199 if (TextUtils.isEmpty(text)) text = "";
200 return TextRecord.newTextRecord(text, Locale.getDefault(), true);
203 public static final Parcelable.Creator<TextRecordEditInfo> CREATOR =
204 new Parcelable.Creator<TextRecordEditInfo>() {
206 public TextRecordEditInfo createFromParcel(Parcel in) {
207 return new TextRecordEditInfo(in);
211 public TextRecordEditInfo[] newArray(int size) {
212 return new TextRecordEditInfo[size];