Tag.java revision ce3224cda51f946871daa1e11e3976e25c59e6fa
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, etc. 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 NfcAdapter#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 NfcAdapter#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 /*package*/ TagTechnology getTechnology(NfcAdapter adapter, int tech) { 131 int pos = -1; 132 for (int idx = 0; idx < mTechList.length; idx++) { 133 if (mTechList[idx] == tech) { 134 pos = idx; 135 break; 136 } 137 } 138 if (pos < 0) { 139 return null; 140 } 141 142 Bundle extras = mTechExtras[pos]; 143 try { 144 switch (tech) { 145 case TagTechnology.NFC_A: { 146 return new NfcA(adapter, this, extras); 147 } 148 case TagTechnology.NFC_B: { 149 return new NfcB(adapter, this, extras); 150 } 151 case TagTechnology.ISO_DEP: { 152 return new IsoDep(adapter, this, extras); 153 } 154 case TagTechnology.NFC_V: { 155 return new NfcV(adapter, this, extras); 156 } 157 case TagTechnology.NDEF: { 158 return new Ndef(adapter, this, tech, extras); 159 } 160 case TagTechnology.NDEF_FORMATABLE: { 161 return new NdefFormatable(adapter, this, tech, extras); 162 } 163 case TagTechnology.NFC_F: { 164 return new NfcF(adapter, this, extras); 165 } 166 case TagTechnology.MIFARE_CLASSIC: { 167 return new MifareClassic(adapter, this, extras); 168 } 169 case TagTechnology.MIFARE_ULTRALIGHT: { 170 return new MifareUltralight(adapter, this, extras); 171 } 172 173 default: { 174 throw new UnsupportedOperationException("Tech " + tech + " not supported"); 175 } 176 } 177 } catch (RemoteException e) { 178 return null; 179 } 180 } 181 182 @Override 183 public String toString() { 184 StringBuilder sb = new StringBuilder("TAG ") 185 .append("uid = ") 186 .append(mId) 187 .append(" Tech ["); 188 for (int i : mTechList) { 189 sb.append(i) 190 .append(", "); 191 } 192 return sb.toString(); 193 } 194 195 /*package*/ static byte[] readBytesWithNull(Parcel in) { 196 int len = in.readInt(); 197 byte[] result = null; 198 if (len >= 0) { 199 result = new byte[len]; 200 in.readByteArray(result); 201 } 202 return result; 203 } 204 205 /*package*/ static void writeBytesWithNull(Parcel out, byte[] b) { 206 if (b == null) { 207 out.writeInt(-1); 208 return; 209 } 210 out.writeInt(b.length); 211 out.writeByteArray(b); 212 } 213 214 @Override 215 public int describeContents() { 216 return 0; 217 } 218 219 @Override 220 public void writeToParcel(Parcel dest, int flags) { 221 writeBytesWithNull(dest, mId); 222 dest.writeInt(mTechList.length); 223 dest.writeIntArray(mTechList); 224 dest.writeTypedArray(mTechExtras, 0); 225 dest.writeInt(mServiceHandle); 226 } 227 228 public static final Parcelable.Creator<Tag> CREATOR = 229 new Parcelable.Creator<Tag>() { 230 @Override 231 public Tag createFromParcel(Parcel in) { 232 // Tag fields 233 byte[] id = Tag.readBytesWithNull(in); 234 int[] techList = new int[in.readInt()]; 235 in.readIntArray(techList); 236 Bundle[] techExtras = in.createTypedArray(Bundle.CREATOR); 237 int serviceHandle = in.readInt(); 238 239 return new Tag(id, techList, techExtras, serviceHandle); 240 } 241 242 @Override 243 public Tag[] newArray(int size) { 244 return new Tag[size]; 245 } 246 }; 247 248 /** 249 * For internal use only. 250 * 251 * @hide 252 */ 253 public synchronized void setConnectedTechnology(int technology) { 254 if (mConnectedTechnology == -1) { 255 mConnectedTechnology = technology; 256 } else { 257 throw new IllegalStateException("Close other technology first!"); 258 } 259 } 260 261 /** 262 * For internal use only. 263 * 264 * @hide 265 */ 266 public int getConnectedTechnology() { 267 return mConnectedTechnology; 268 } 269 270 /** 271 * For internal use only. 272 * 273 * @hide 274 */ 275 public void setTechnologyDisconnected() { 276 mConnectedTechnology = -1; 277 } 278} 279