Home | History | Annotate | Download | only in record
      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 
     17 package com.android.apps.tag.record;
     18 
     19 import com.android.apps.tag.R;
     20 import com.google.common.annotations.VisibleForTesting;
     21 import com.google.common.base.Preconditions;
     22 import com.google.common.primitives.Bytes;
     23 
     24 import android.app.Activity;
     25 import android.content.Context;
     26 import android.nfc.NdefRecord;
     27 import android.view.LayoutInflater;
     28 import android.view.View;
     29 import android.view.ViewGroup;
     30 import android.widget.TextView;
     31 
     32 import java.io.UnsupportedEncodingException;
     33 import java.nio.charset.Charset;
     34 import java.util.Arrays;
     35 import java.util.Locale;
     36 
     37 /**
     38  * An NFC Text Record
     39  */
     40 public class TextRecord extends ParsedNdefRecord {
     41 
     42     public static final String RECORD_TYPE = "TextRecord";
     43 
     44     /** ISO/IANA language code */
     45     private final String mLanguageCode;
     46     private final String mText;
     47 
     48     private TextRecord(String languageCode, String text) {
     49         mLanguageCode = Preconditions.checkNotNull(languageCode);
     50         mText = Preconditions.checkNotNull(text);
     51     }
     52 
     53     @Override
     54     public View getView(Activity activity, LayoutInflater inflater, ViewGroup parent, int offset) {
     55         TextView text = (TextView) inflater.inflate(R.layout.tag_text, parent, false);
     56         text.setText(mText);
     57         return text;
     58     }
     59 
     60     @Override
     61     public String getSnippet(Context context, Locale locale) {
     62         return mText;
     63     }
     64 
     65     public String getText() {
     66         return mText;
     67     }
     68 
     69     /**
     70      * Returns the ISO/IANA language code associated with this text element.
     71      *
     72      * TODO: this should return a {@link java.util.Locale}
     73      */
     74     @VisibleForTesting
     75     public String getLanguageCode() {
     76         return mLanguageCode;
     77     }
     78 
     79     // TODO: deal with text fields which span multiple NdefRecords
     80     public static TextRecord parse(NdefRecord record) {
     81         Preconditions.checkArgument(record.getTnf() == NdefRecord.TNF_WELL_KNOWN);
     82         Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.RTD_TEXT));
     83         try {
     84 
     85             byte[] payload = record.getPayload();
     86             Preconditions.checkArgument(payload.length > 0);
     87 
     88             /*
     89              * payload[0] contains the "Status Byte Encodings" field, per
     90              * the NFC Forum "Text Record Type Definition" section 3.2.1.
     91              *
     92              * bit7 is the Text Encoding Field.
     93              *
     94              * if (Bit_7 == 0): The text is encoded in UTF-8
     95              * if (Bit_7 == 1): The text is encoded in UTF16
     96              *
     97              * Bit_6 is reserved for future use and must be set to zero.
     98              *
     99              * Bits 5 to 0 are the length of the IANA language code.
    100              */
    101 
    102             String textEncoding = ((payload[0] & 0200) == 0) ? "UTF-8" : "UTF-16";
    103             int languageCodeLength = payload[0] & 0077;
    104             Preconditions.checkArgument(payload.length - languageCodeLength - 1 >= 0);
    105 
    106             String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
    107             String text = new String(payload,
    108                     languageCodeLength + 1,
    109                     payload.length - languageCodeLength - 1,
    110                     textEncoding);
    111             return new TextRecord(languageCode, text);
    112 
    113         } catch (UnsupportedEncodingException e) {
    114             // should never happen unless we get a malformed tag.
    115             throw new IllegalArgumentException(e);
    116         }
    117     }
    118 
    119     public static boolean isText(NdefRecord record) {
    120         try {
    121             parse(record);
    122             return true;
    123         } catch (IllegalArgumentException e) {
    124             return false;
    125         }
    126     }
    127 
    128     @VisibleForTesting
    129     public static NdefRecord newTextRecord(String text, Locale locale) {
    130         return newTextRecord(text, locale, true);
    131     }
    132 
    133     public static NdefRecord newTextRecord(String text, Locale locale, boolean encodeInUtf8) {
    134         Preconditions.checkNotNull(text);
    135         Preconditions.checkNotNull(locale);
    136 
    137         byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
    138 
    139         Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");
    140         byte[] textBytes = text.getBytes(utfEncoding);
    141 
    142         int utfBit = encodeInUtf8 ? 0 : (1 << 7);
    143         char status = (char) (utfBit + langBytes.length);
    144 
    145         byte[] data = Bytes.concat(
    146            new byte[] { (byte) status },
    147            langBytes,
    148            textBytes
    149         );
    150 
    151         return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], data);
    152     }
    153 }
    154