Tag.java revision be372d6462605010910e771cef15d5adccd0a59e
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 android.nfc; 18 19import android.nfc.technology.IsoDep; 20import android.nfc.technology.MifareClassic; 21import android.nfc.technology.MifareUltralight; 22import android.nfc.technology.NfcV; 23import android.nfc.technology.Ndef; 24import android.nfc.technology.NdefFormatable; 25import android.nfc.technology.NfcA; 26import android.nfc.technology.NfcB; 27import android.nfc.technology.NfcF; 28import android.nfc.technology.TagTechnology; 29import android.os.Bundle; 30import android.os.Parcel; 31import android.os.Parcelable; 32import android.os.RemoteException; 33 34import java.util.Arrays; 35 36/** 37 * Represents a (generic) discovered tag. 38 * <p> 39 * A tag is a passive NFC element, such as NFC Forum Tag's, Mifare class Tags, 40 * Sony Felica Tags. 41 * <p> 42 * Tag's have a type and usually have a UID. 43 * <p> 44 * {@link Tag} objects are passed to applications via the {@link NfcAdapter#EXTRA_TAG} extra 45 * in {@link NfcAdapter#ACTION_TAG_DISCOVERED} intents. A {@link Tag} object is immutable 46 * and represents the state of the tag at the time of discovery. It can be 47 * directly queried for its UID and Type, or used to create a {@link TagTechnology} 48 * (with {@link Tag#getTechnology}). 49 * <p> 50 * A {@link Tag} can be used to create a {@link TagTechnology} only while the tag is in 51 * range. If it is removed and then returned to range, then the most recent 52 * {@link Tag} object (in {@link NfcAdapter#ACTION_TAG_DISCOVERED}) should be used to create a 53 * {@link TagTechnology}. 54 * <p>This is an immutable data class. All properties are set at Tag discovery 55 * time and calls on this class will retrieve those read-only properties, and 56 * not cause any further RF activity or block. Note however that arrays passed to and 57 * returned by this class are *not* cloned, so be careful not to modify them. 58 */ 59public class Tag implements Parcelable { 60 /*package*/ final byte[] mId; 61 /*package*/ final int[] mTechList; 62 /*package*/ final Bundle[] mTechExtras; 63 /*package*/ final int mServiceHandle; // for use by NFC service, 0 indicates a mock 64 65 /*package*/ int mConnectedTechnology; 66 67 /** 68 * Hidden constructor to be used by NFC service and internal classes. 69 * @hide 70 */ 71 public Tag(byte[] id, int[] techList, Bundle[] techListExtras, int serviceHandle) { 72 if (techList == null) { 73 throw new IllegalArgumentException("rawTargets cannot be null"); 74 } 75 mId = id; 76 mTechList = Arrays.copyOf(techList, techList.length); 77 // Ensure mTechExtras is as long as mTechList 78 mTechExtras = Arrays.copyOf(techListExtras, techList.length); 79 mServiceHandle = serviceHandle; 80 81 mConnectedTechnology = -1; 82 } 83 84 /** 85 * Construct a mock Tag. 86 * <p>This is an application constructed tag, so NfcAdapter methods on this 87 * Tag such as {@link #getTechnology} may fail with 88 * {@link IllegalArgumentException} since it does not represent a physical Tag. 89 * <p>This constructor might be useful for mock testing. 90 * @param id The tag identifier, can be null 91 * @param techList must not be null 92 * @return freshly constructed tag 93 */ 94 public static Tag createMockTag(byte[] id, int[] techList, Bundle[] techListExtras) { 95 // set serviceHandle to 0 to indicate mock tag 96 return new Tag(id, techList, techListExtras, 0); 97 } 98 99 /** 100 * For use by NfcService only. 101 * @hide 102 */ 103 public int getServiceHandle() { 104 return mServiceHandle; 105 } 106 107 /** 108 * Get the Tag Identifier (if it has one). 109 * <p>Tag ID is usually a serial number for the tag. 110 * 111 * @return ID, or null if it does not exist 112 */ 113 public byte[] getId() { 114 return mId; 115 } 116 117 /** 118 * Returns technologies present in the tag that this implementation understands, 119 * or a zero length array if there are no supported technologies on this tag. 120 * 121 * The elements of the list are guaranteed be one of the constants defined in 122 * {@link TagTechnology}. 123 * 124 * The ordering of the returned array is undefined and should not be relied upon. 125 */ 126 public int[] getTechnologyList() { 127 return Arrays.copyOf(mTechList, mTechList.length); 128 } 129 130 /** 131 * Returns the technology, or null if not present 132 */ 133 public TagTechnology getTechnology(NfcAdapter adapter, int tech) { 134 int pos = -1; 135 for (int idx = 0; idx < mTechList.length; idx++) { 136 if (mTechList[idx] == tech) { 137 pos = idx; 138 break; 139 } 140 } 141 if (pos < 0) { 142 return null; 143 } 144 145 Bundle extras = mTechExtras[pos]; 146 try { 147 switch (tech) { 148 case TagTechnology.NFC_A: { 149 return new NfcA(adapter, this, extras); 150 } 151 case TagTechnology.NFC_B: { 152 return new NfcB(adapter, this, extras); 153 } 154 case TagTechnology.ISO_DEP: { 155 return new IsoDep(adapter, this, extras); 156 } 157 case TagTechnology.NFC_V: { 158 return new NfcV(adapter, this, extras); 159 } 160 case TagTechnology.NDEF: { 161 return new Ndef(adapter, this, tech, extras); 162 } 163 case TagTechnology.NDEF_FORMATABLE: { 164 return new NdefFormatable(adapter, this, tech, extras); 165 } 166 case TagTechnology.NFC_F: { 167 return new NfcF(adapter, this, extras); 168 } 169 case TagTechnology.MIFARE_CLASSIC: { 170 return new MifareClassic(adapter, this, extras); 171 } 172 case TagTechnology.MIFARE_ULTRALIGHT: { 173 return new MifareUltralight(adapter, this, extras); 174 } 175 176 default: { 177 throw new UnsupportedOperationException("Tech " + tech + " not supported"); 178 } 179 } 180 } catch (RemoteException e) { 181 return null; 182 } 183 } 184 185 @Override 186 public String toString() { 187 StringBuilder sb = new StringBuilder("TAG ") 188 .append("uid = ") 189 .append(mId) 190 .append(" Tech ["); 191 for (int i : mTechList) { 192 sb.append(i) 193 .append(", "); 194 } 195 return sb.toString(); 196 } 197 198 /*package*/ static byte[] readBytesWithNull(Parcel in) { 199 int len = in.readInt(); 200 byte[] result = null; 201 if (len >= 0) { 202 result = new byte[len]; 203 in.readByteArray(result); 204 } 205 return result; 206 } 207 208 /*package*/ static void writeBytesWithNull(Parcel out, byte[] b) { 209 if (b == null) { 210 out.writeInt(-1); 211 return; 212 } 213 out.writeInt(b.length); 214 out.writeByteArray(b); 215 } 216 217 @Override 218 public int describeContents() { 219 return 0; 220 } 221 222 @Override 223 public void writeToParcel(Parcel dest, int flags) { 224 writeBytesWithNull(dest, mId); 225 dest.writeInt(mTechList.length); 226 dest.writeIntArray(mTechList); 227 dest.writeTypedArray(mTechExtras, 0); 228 dest.writeInt(mServiceHandle); 229 } 230 231 public static final Parcelable.Creator<Tag> CREATOR = 232 new Parcelable.Creator<Tag>() { 233 @Override 234 public Tag createFromParcel(Parcel in) { 235 // Tag fields 236 byte[] id = Tag.readBytesWithNull(in); 237 int[] techList = new int[in.readInt()]; 238 in.readIntArray(techList); 239 Bundle[] techExtras = in.createTypedArray(Bundle.CREATOR); 240 int serviceHandle = in.readInt(); 241 242 return new Tag(id, techList, techExtras, serviceHandle); 243 } 244 245 @Override 246 public Tag[] newArray(int size) { 247 return new Tag[size]; 248 } 249 }; 250 251 /** 252 * For internal use only. 253 * 254 * @hide 255 */ 256 public synchronized void setConnectedTechnology(int technology) { 257 if (mConnectedTechnology == -1) { 258 mConnectedTechnology = technology; 259 } else { 260 throw new IllegalStateException("Close other technology first!"); 261 } 262 } 263 264 /** 265 * For internal use only. 266 * 267 * @hide 268 */ 269 public int getConnectedTechnology() { 270 return mConnectedTechnology; 271 } 272 273 /** 274 * For internal use only. 275 * 276 * @hide 277 */ 278 public void setTechnologyDisconnected() { 279 mConnectedTechnology = -1; 280 } 281} 282