Tag.java revision f003e26df96067b4b136f0859012cb7ec3ed930f
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 final 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 * @hide 97 */ 98 public static Tag createMockTag(byte[] id, int[] techList, Bundle[] techListExtras) { 99 // set serviceHandle to 0 to indicate mock tag 100 return new Tag(id, techList, techListExtras, 0, null); 101 } 102 103 private String[] generateTechStringList(int[] techList) { 104 final int size = techList.length; 105 String[] strings = new String[size]; 106 for (int i = 0; i < size; i++) { 107 switch (techList[i]) { 108 case TagTechnology.ISO_DEP: 109 strings[i] = IsoDep.class.getName(); 110 break; 111 case TagTechnology.MIFARE_CLASSIC: 112 strings[i] = MifareClassic.class.getName(); 113 break; 114 case TagTechnology.MIFARE_ULTRALIGHT: 115 strings[i] = MifareUltralight.class.getName(); 116 break; 117 case TagTechnology.NDEF: 118 strings[i] = Ndef.class.getName(); 119 break; 120 case TagTechnology.NDEF_FORMATABLE: 121 strings[i] = NdefFormatable.class.getName(); 122 break; 123 case TagTechnology.NFC_A: 124 strings[i] = NfcA.class.getName(); 125 break; 126 case TagTechnology.NFC_B: 127 strings[i] = NfcB.class.getName(); 128 break; 129 case TagTechnology.NFC_F: 130 strings[i] = NfcF.class.getName(); 131 break; 132 case TagTechnology.NFC_V: 133 strings[i] = NfcV.class.getName(); 134 break; 135 default: 136 throw new IllegalArgumentException("Unknown tech type " + techList[i]); 137 } 138 } 139 return strings; 140 } 141 142 /** 143 * For use by NfcService only. 144 * @hide 145 */ 146 public int getServiceHandle() { 147 return mServiceHandle; 148 } 149 150 /** 151 * Get the Tag Identifier (if it has one). 152 * <p>Tag ID is usually a serial number for the tag. 153 * 154 * @return ID, or null if it does not exist 155 */ 156 public byte[] getId() { 157 return mId; 158 } 159 160 /** 161 * Returns technologies present in the tag that this implementation understands, 162 * or a zero length array if there are no supported technologies on this tag. 163 * 164 * The elements of the list are the names of the classes implementing the technology. 165 * 166 * The ordering of the returned array is undefined and should not be relied upon. 167 */ 168 public String[] getTechList() { 169 return mTechStringList; 170 } 171 172 /** @hide */ 173 public boolean hasTech(int techType) { 174 for (int tech : mTechList) { 175 if (tech == techType) return true; 176 } 177 return false; 178 } 179 180 /** @hide */ 181 public Bundle getTechExtras(int tech) { 182 int pos = -1; 183 for (int idx = 0; idx < mTechList.length; idx++) { 184 if (mTechList[idx] == tech) { 185 pos = idx; 186 break; 187 } 188 } 189 if (pos < 0) { 190 return null; 191 } 192 193 return mTechExtras[pos]; 194 } 195 196 /** @hide */ 197 public INfcTag getTagService() { 198 return mTagService; 199 } 200 201 @Override 202 public String toString() { 203 StringBuilder sb = new StringBuilder("TAG ") 204 .append("uid = ") 205 .append(mId) 206 .append(" Tech ["); 207 for (int i : mTechList) { 208 sb.append(i) 209 .append(", "); 210 } 211 return sb.toString(); 212 } 213 214 /*package*/ static byte[] readBytesWithNull(Parcel in) { 215 int len = in.readInt(); 216 byte[] result = null; 217 if (len >= 0) { 218 result = new byte[len]; 219 in.readByteArray(result); 220 } 221 return result; 222 } 223 224 /*package*/ static void writeBytesWithNull(Parcel out, byte[] b) { 225 if (b == null) { 226 out.writeInt(-1); 227 return; 228 } 229 out.writeInt(b.length); 230 out.writeByteArray(b); 231 } 232 233 @Override 234 public int describeContents() { 235 return 0; 236 } 237 238 @Override 239 public void writeToParcel(Parcel dest, int flags) { 240 // Null mTagService means this is a mock tag 241 int isMock = (mTagService == null)?1:0; 242 243 writeBytesWithNull(dest, mId); 244 dest.writeInt(mTechList.length); 245 dest.writeIntArray(mTechList); 246 dest.writeTypedArray(mTechExtras, 0); 247 dest.writeInt(mServiceHandle); 248 dest.writeInt(isMock); 249 if (isMock == 0) { 250 dest.writeStrongBinder(mTagService.asBinder()); 251 } 252 } 253 254 public static final Parcelable.Creator<Tag> CREATOR = 255 new Parcelable.Creator<Tag>() { 256 @Override 257 public Tag createFromParcel(Parcel in) { 258 INfcTag tagService; 259 260 // Tag fields 261 byte[] id = Tag.readBytesWithNull(in); 262 int[] techList = new int[in.readInt()]; 263 in.readIntArray(techList); 264 Bundle[] techExtras = in.createTypedArray(Bundle.CREATOR); 265 int serviceHandle = in.readInt(); 266 int isMock = in.readInt(); 267 if (isMock == 0) { 268 tagService = INfcTag.Stub.asInterface(in.readStrongBinder()); 269 } 270 else { 271 tagService = null; 272 } 273 274 return new Tag(id, techList, techExtras, serviceHandle, tagService); 275 } 276 277 @Override 278 public Tag[] newArray(int size) { 279 return new Tag[size]; 280 } 281 }; 282 283 /** 284 * For internal use only. 285 * 286 * @hide 287 */ 288 public synchronized void setConnectedTechnology(int technology) { 289 if (mConnectedTechnology == -1) { 290 mConnectedTechnology = technology; 291 } else { 292 throw new IllegalStateException("Close other technology first!"); 293 } 294 } 295 296 /** 297 * For internal use only. 298 * 299 * @hide 300 */ 301 public int getConnectedTechnology() { 302 return mConnectedTechnology; 303 } 304 305 /** 306 * For internal use only. 307 * 308 * @hide 309 */ 310 public void setTechnologyDisconnected() { 311 mConnectedTechnology = -1; 312 } 313} 314