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