Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 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 android.nfc; |
| 18 | |
Mathew Inwood | 57069dc | 2018-07-31 15:33:20 +0100 | [diff] [blame] | 19 | import android.annotation.UnsupportedAppUsage; |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 20 | import android.content.Context; |
Jeff Hamilton | d88e9aa | 2011-01-24 14:53:00 -0600 | [diff] [blame] | 21 | import android.nfc.tech.IsoDep; |
| 22 | import android.nfc.tech.MifareClassic; |
| 23 | import android.nfc.tech.MifareUltralight; |
| 24 | import android.nfc.tech.Ndef; |
| 25 | import android.nfc.tech.NdefFormatable; |
| 26 | import android.nfc.tech.NfcA; |
| 27 | import android.nfc.tech.NfcB; |
Martijn Coenen | ca0cf4e | 2012-09-24 16:38:57 -0700 | [diff] [blame] | 28 | import android.nfc.tech.NfcBarcode; |
Jeff Hamilton | d88e9aa | 2011-01-24 14:53:00 -0600 | [diff] [blame] | 29 | import android.nfc.tech.NfcF; |
| 30 | import android.nfc.tech.NfcV; |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 31 | import android.nfc.tech.TagTechnology; |
Jeff Hamilton | 6be655c | 2010-11-12 12:28:16 -0600 | [diff] [blame] | 32 | import android.os.Bundle; |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 33 | import android.os.Parcel; |
| 34 | import android.os.Parcelable; |
Martijn Coenen | 2dcae567 | 2011-06-02 16:02:00 -0700 | [diff] [blame] | 35 | import android.os.RemoteException; |
Jeff Hamilton | 6be655c | 2010-11-12 12:28:16 -0600 | [diff] [blame] | 36 | |
Martijn Coenen | 2dcae567 | 2011-06-02 16:02:00 -0700 | [diff] [blame] | 37 | import java.io.IOException; |
Jeff Hamilton | 6be655c | 2010-11-12 12:28:16 -0600 | [diff] [blame] | 38 | import java.util.Arrays; |
Andres Morales | d8cf53f | 2014-06-20 14:32:47 -0700 | [diff] [blame] | 39 | import java.util.HashMap; |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 40 | |
| 41 | /** |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 42 | * Represents an NFC tag that has been discovered. |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 43 | * <p> |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 44 | * {@link Tag} is an immutable object that represents the state of a NFC tag at |
| 45 | * the time of discovery. It can be used as a handle to {@link TagTechnology} classes |
Jeff Hamilton | 28319c0 | 2011-02-09 17:26:47 +0900 | [diff] [blame] | 46 | * to perform advanced operations, or directly queried for its ID via {@link #getId} and the |
| 47 | * set of technologies it contains via {@link #getTechList}. Arrays passed to and |
| 48 | * returned by this class are <em>not</em> cloned, so be careful not to modify them. |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 49 | * <p> |
| 50 | * A new tag object is created every time a tag is discovered (comes into range), even |
| 51 | * if it is the same physical tag. If a tag is removed and then returned into range, then |
| 52 | * only the most recent tag object can be successfully used to create a {@link TagTechnology}. |
| 53 | * |
| 54 | * <h3>Tag Dispatch</h3> |
| 55 | * When a tag is discovered, a {@link Tag} object is created and passed to a |
Jeff Hamilton | 28319c0 | 2011-02-09 17:26:47 +0900 | [diff] [blame] | 56 | * single activity via the {@link NfcAdapter#EXTRA_TAG} extra in an |
| 57 | * {@link android.content.Intent} via {@link Context#startActivity}. A four stage dispatch is used |
| 58 | * to select the |
| 59 | * most appropriate activity to handle the tag. The Android OS executes each stage in order, |
| 60 | * and completes dispatch as soon as a single matching activity is found. If there are multiple |
| 61 | * matching activities found at any one stage then the Android activity chooser dialog is shown |
| 62 | * to allow the user to select the activity to receive the tag. |
| 63 | * |
| 64 | * <p>The Tag dispatch mechanism was designed to give a high probability of dispatching |
| 65 | * a tag to the correct activity without showing the user an activity chooser dialog. |
| 66 | * This is important for NFC interactions because they are very transient -- if a user has to |
| 67 | * move the Android device to choose an application then the connection will likely be broken. |
| 68 | * |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 69 | * <h4>1. Foreground activity dispatch</h4> |
Jeff Hamilton | 28319c0 | 2011-02-09 17:26:47 +0900 | [diff] [blame] | 70 | * A foreground activity that has called |
| 71 | * {@link NfcAdapter#enableForegroundDispatch NfcAdapter.enableForegroundDispatch()} is |
| 72 | * given priority. See the documentation on |
| 73 | * {@link NfcAdapter#enableForegroundDispatch NfcAdapter.enableForegroundDispatch()} for |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 74 | * its usage. |
| 75 | * <h4>2. NDEF data dispatch</h4> |
Jeff Hamilton | 28319c0 | 2011-02-09 17:26:47 +0900 | [diff] [blame] | 76 | * If the tag contains NDEF data the system inspects the first {@link NdefRecord} in the first |
| 77 | * {@link NdefMessage}. If the record is a URI, SmartPoster, or MIME data |
| 78 | * {@link Context#startActivity} is called with {@link NfcAdapter#ACTION_NDEF_DISCOVERED}. For URI |
| 79 | * and SmartPoster records the URI is put into the intent's data field. For MIME records the MIME |
| 80 | * type is put in the intent's type field. This allows activities to register to be launched only |
| 81 | * when data they know how to handle is present on a tag. This is the preferred method of handling |
| 82 | * data on a tag since NDEF data can be stored on many types of tags and doesn't depend on a |
| 83 | * specific tag technology. |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 84 | * See {@link NfcAdapter#ACTION_NDEF_DISCOVERED} for more detail. If the tag does not contain |
Jeff Hamilton | 28319c0 | 2011-02-09 17:26:47 +0900 | [diff] [blame] | 85 | * NDEF data, or if no activity is registered |
| 86 | * for {@link NfcAdapter#ACTION_NDEF_DISCOVERED} with a matching data URI or MIME type then dispatch |
| 87 | * moves to stage 3. |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 88 | * <h4>3. Tag Technology dispatch</h4> |
| 89 | * {@link Context#startActivity} is called with {@link NfcAdapter#ACTION_TECH_DISCOVERED} to |
Jeff Hamilton | 28319c0 | 2011-02-09 17:26:47 +0900 | [diff] [blame] | 90 | * dispatch the tag to an activity that can handle the technologies present on the tag. |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 91 | * Technologies are defined as sub-classes of {@link TagTechnology}, see the package |
Jeff Hamilton | 28319c0 | 2011-02-09 17:26:47 +0900 | [diff] [blame] | 92 | * {@link android.nfc.tech}. The Android OS looks for an activity that can handle one or |
| 93 | * more technologies in the tag. See {@link NfcAdapter#ACTION_TECH_DISCOVERED} for more detail. |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 94 | * <h4>4. Fall-back dispatch</h4> |
Jeff Hamilton | 28319c0 | 2011-02-09 17:26:47 +0900 | [diff] [blame] | 95 | * If no activity has been matched then {@link Context#startActivity} is called with |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 96 | * {@link NfcAdapter#ACTION_TAG_DISCOVERED}. This is intended as a fall-back mechanism. |
| 97 | * See {@link NfcAdapter#ACTION_TAG_DISCOVERED}. |
| 98 | * |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 99 | * <h3>NFC Tag Background</h3> |
| 100 | * An NFC tag is a passive NFC device, powered by the NFC field of this Android device while |
Jeff Hamilton | 28319c0 | 2011-02-09 17:26:47 +0900 | [diff] [blame] | 101 | * it is in range. Tag's can come in many forms, such as stickers, cards, key fobs, or |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 102 | * even embedded in a more sophisticated device. |
| 103 | * <p> |
| 104 | * Tags can have a wide range of capabilities. Simple tags just offer read/write semantics, |
| 105 | * and contain some one time |
| 106 | * programmable areas to make read-only. More complex tags offer math operations |
| 107 | * and per-sector access control and authentication. The most sophisticated tags |
Jeff Hamilton | 28319c0 | 2011-02-09 17:26:47 +0900 | [diff] [blame] | 108 | * contain operating environments allowing complex interactions with the |
| 109 | * code executing on the tag. Use {@link TagTechnology} classes to access a broad |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 110 | * range of capabilities available in NFC tags. |
| 111 | * <p> |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 112 | */ |
Nick Pelly | f003e26 | 2011-01-31 23:27:37 -0800 | [diff] [blame] | 113 | public final class Tag implements Parcelable { |
Mathew Inwood | 57069dc | 2018-07-31 15:33:20 +0100 | [diff] [blame] | 114 | @UnsupportedAppUsage |
Nick Pelly | 1f5badc | 2012-01-24 13:22:58 -0800 | [diff] [blame] | 115 | final byte[] mId; |
| 116 | final int[] mTechList; |
| 117 | final String[] mTechStringList; |
| 118 | final Bundle[] mTechExtras; |
| 119 | final int mServiceHandle; // for use by NFC service, 0 indicates a mock |
| 120 | final INfcTag mTagService; // interface to NFC service, will be null if mock tag |
Sylvain Fonteneau | a926540 | 2010-10-15 14:41:22 -0700 | [diff] [blame] | 121 | |
Nick Pelly | 1f5badc | 2012-01-24 13:22:58 -0800 | [diff] [blame] | 122 | int mConnectedTechnology; |
Martijn Coenen | 4049f9d0 | 2010-12-14 16:58:27 +0100 | [diff] [blame] | 123 | |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 124 | /** |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 125 | * Hidden constructor to be used by NFC service and internal classes. |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 126 | * @hide |
| 127 | */ |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 128 | public Tag(byte[] id, int[] techList, Bundle[] techListExtras, int serviceHandle, |
| 129 | INfcTag tagService) { |
Jeff Hamilton | 6be655c | 2010-11-12 12:28:16 -0600 | [diff] [blame] | 130 | if (techList == null) { |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 131 | throw new IllegalArgumentException("rawTargets cannot be null"); |
| 132 | } |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 133 | mId = id; |
Jeff Hamilton | 6be655c | 2010-11-12 12:28:16 -0600 | [diff] [blame] | 134 | mTechList = Arrays.copyOf(techList, techList.length); |
Jeff Hamilton | d88e9aa | 2011-01-24 14:53:00 -0600 | [diff] [blame] | 135 | mTechStringList = generateTechStringList(techList); |
Jeff Hamilton | 6be655c | 2010-11-12 12:28:16 -0600 | [diff] [blame] | 136 | // Ensure mTechExtras is as long as mTechList |
| 137 | mTechExtras = Arrays.copyOf(techListExtras, techList.length); |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 138 | mServiceHandle = serviceHandle; |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 139 | mTagService = tagService; |
Martijn Coenen | 4049f9d0 | 2010-12-14 16:58:27 +0100 | [diff] [blame] | 140 | |
| 141 | mConnectedTechnology = -1; |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 142 | } |
| 143 | |
| 144 | /** |
| 145 | * Construct a mock Tag. |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 146 | * <p>This is an application constructed tag, so NfcAdapter methods on this Tag may fail |
| 147 | * with {@link IllegalArgumentException} since it does not represent a physical Tag. |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 148 | * <p>This constructor might be useful for mock testing. |
| 149 | * @param id The tag identifier, can be null |
Jeff Hamilton | 6be655c | 2010-11-12 12:28:16 -0600 | [diff] [blame] | 150 | * @param techList must not be null |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 151 | * @return freshly constructed tag |
Nick Pelly | f003e26 | 2011-01-31 23:27:37 -0800 | [diff] [blame] | 152 | * @hide |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 153 | */ |
Jeff Hamilton | 6be655c | 2010-11-12 12:28:16 -0600 | [diff] [blame] | 154 | public static Tag createMockTag(byte[] id, int[] techList, Bundle[] techListExtras) { |
Martijn Coenen | 23fc93a | 2011-11-28 10:43:14 -0800 | [diff] [blame] | 155 | // set serviceHandle to 0 and tagService to null to indicate mock tag |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 156 | return new Tag(id, techList, techListExtras, 0, null); |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 157 | } |
| 158 | |
Jeff Hamilton | d88e9aa | 2011-01-24 14:53:00 -0600 | [diff] [blame] | 159 | private String[] generateTechStringList(int[] techList) { |
| 160 | final int size = techList.length; |
| 161 | String[] strings = new String[size]; |
| 162 | for (int i = 0; i < size; i++) { |
| 163 | switch (techList[i]) { |
| 164 | case TagTechnology.ISO_DEP: |
| 165 | strings[i] = IsoDep.class.getName(); |
| 166 | break; |
| 167 | case TagTechnology.MIFARE_CLASSIC: |
| 168 | strings[i] = MifareClassic.class.getName(); |
| 169 | break; |
| 170 | case TagTechnology.MIFARE_ULTRALIGHT: |
| 171 | strings[i] = MifareUltralight.class.getName(); |
| 172 | break; |
| 173 | case TagTechnology.NDEF: |
| 174 | strings[i] = Ndef.class.getName(); |
| 175 | break; |
| 176 | case TagTechnology.NDEF_FORMATABLE: |
| 177 | strings[i] = NdefFormatable.class.getName(); |
| 178 | break; |
| 179 | case TagTechnology.NFC_A: |
| 180 | strings[i] = NfcA.class.getName(); |
| 181 | break; |
| 182 | case TagTechnology.NFC_B: |
| 183 | strings[i] = NfcB.class.getName(); |
| 184 | break; |
| 185 | case TagTechnology.NFC_F: |
| 186 | strings[i] = NfcF.class.getName(); |
| 187 | break; |
| 188 | case TagTechnology.NFC_V: |
| 189 | strings[i] = NfcV.class.getName(); |
| 190 | break; |
Martijn Coenen | ca0cf4e | 2012-09-24 16:38:57 -0700 | [diff] [blame] | 191 | case TagTechnology.NFC_BARCODE: |
| 192 | strings[i] = NfcBarcode.class.getName(); |
| 193 | break; |
Jeff Hamilton | d88e9aa | 2011-01-24 14:53:00 -0600 | [diff] [blame] | 194 | default: |
| 195 | throw new IllegalArgumentException("Unknown tech type " + techList[i]); |
| 196 | } |
| 197 | } |
| 198 | return strings; |
| 199 | } |
| 200 | |
Andres Morales | 11d2e53 | 2014-07-23 12:39:55 -0700 | [diff] [blame] | 201 | static int[] getTechCodesFromStrings(String[] techStringList) throws IllegalArgumentException { |
Andres Morales | d8cf53f | 2014-06-20 14:32:47 -0700 | [diff] [blame] | 202 | if (techStringList == null) { |
| 203 | throw new IllegalArgumentException("List cannot be null"); |
| 204 | } |
| 205 | int[] techIntList = new int[techStringList.length]; |
| 206 | HashMap<String, Integer> stringToCodeMap = getTechStringToCodeMap(); |
| 207 | for (int i = 0; i < techStringList.length; i++) { |
| 208 | Integer code = stringToCodeMap.get(techStringList[i]); |
| 209 | |
| 210 | if (code == null) { |
| 211 | throw new IllegalArgumentException("Unknown tech type " + techStringList[i]); |
| 212 | } |
| 213 | |
| 214 | techIntList[i] = code.intValue(); |
| 215 | } |
| 216 | return techIntList; |
| 217 | } |
| 218 | |
| 219 | private static HashMap<String, Integer> getTechStringToCodeMap() { |
| 220 | HashMap<String, Integer> techStringToCodeMap = new HashMap<String, Integer>(); |
| 221 | |
| 222 | techStringToCodeMap.put(IsoDep.class.getName(), TagTechnology.ISO_DEP); |
| 223 | techStringToCodeMap.put(MifareClassic.class.getName(), TagTechnology.MIFARE_CLASSIC); |
| 224 | techStringToCodeMap.put(MifareUltralight.class.getName(), TagTechnology.MIFARE_ULTRALIGHT); |
| 225 | techStringToCodeMap.put(Ndef.class.getName(), TagTechnology.NDEF); |
| 226 | techStringToCodeMap.put(NdefFormatable.class.getName(), TagTechnology.NDEF_FORMATABLE); |
| 227 | techStringToCodeMap.put(NfcA.class.getName(), TagTechnology.NFC_A); |
| 228 | techStringToCodeMap.put(NfcB.class.getName(), TagTechnology.NFC_B); |
| 229 | techStringToCodeMap.put(NfcF.class.getName(), TagTechnology.NFC_F); |
| 230 | techStringToCodeMap.put(NfcV.class.getName(), TagTechnology.NFC_V); |
| 231 | techStringToCodeMap.put(NfcBarcode.class.getName(), TagTechnology.NFC_BARCODE); |
| 232 | |
| 233 | return techStringToCodeMap; |
| 234 | } |
| 235 | |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 236 | /** |
| 237 | * For use by NfcService only. |
| 238 | * @hide |
| 239 | */ |
Mathew Inwood | 57069dc | 2018-07-31 15:33:20 +0100 | [diff] [blame] | 240 | @UnsupportedAppUsage |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 241 | public int getServiceHandle() { |
| 242 | return mServiceHandle; |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 243 | } |
| 244 | |
| 245 | /** |
Andres Morales | 3e4b665 | 2013-12-12 16:37:09 -0800 | [diff] [blame] | 246 | * For use by NfcService only. |
| 247 | * @hide |
| 248 | */ |
| 249 | public int[] getTechCodeList() { |
| 250 | return mTechList; |
| 251 | } |
| 252 | |
| 253 | /** |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 254 | * Get the Tag Identifier (if it has one). |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 255 | * <p>The tag identifier is a low level serial number, used for anti-collision |
| 256 | * and identification. |
| 257 | * <p> Most tags have a stable unique identifier |
| 258 | * (UID), but some tags will generate a random ID every time they are discovered |
| 259 | * (RID), and there are some tags with no ID at all (the byte array will be zero-sized). |
| 260 | * <p> The size and format of an ID is specific to the RF technology used by the tag. |
| 261 | * <p> This function retrieves the ID as determined at discovery time, and does not |
| 262 | * perform any further RF communication or block. |
| 263 | * @return ID as byte array, never null |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 264 | */ |
| 265 | public byte[] getId() { |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 266 | return mId; |
| 267 | } |
| 268 | |
| 269 | /** |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 270 | * Get the technologies available in this tag, as fully qualified class names. |
| 271 | * <p> |
| 272 | * A technology is an implementation of the {@link TagTechnology} interface, |
| 273 | * and can be instantiated by calling the static <code>get(Tag)</code> |
| 274 | * method on the implementation with this Tag. The {@link TagTechnology} |
| 275 | * object can then be used to perform advanced, technology-specific operations on a tag. |
| 276 | * <p> |
| 277 | * Android defines a mandatory set of technologies that must be correctly |
| 278 | * enumerated by all Android NFC devices, and an optional |
| 279 | * set of proprietary technologies. |
| 280 | * See {@link TagTechnology} for more details. |
| 281 | * <p> |
Jeff Hamilton | c1576ad | 2010-12-05 21:45:22 -0600 | [diff] [blame] | 282 | * The ordering of the returned array is undefined and should not be relied upon. |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 283 | * @return an array of fully-qualified {@link TagTechnology} class-names. |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 284 | */ |
Jeff Hamilton | d88e9aa | 2011-01-24 14:53:00 -0600 | [diff] [blame] | 285 | public String[] getTechList() { |
| 286 | return mTechStringList; |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 287 | } |
| 288 | |
Martijn Coenen | 2dcae567 | 2011-06-02 16:02:00 -0700 | [diff] [blame] | 289 | /** |
| 290 | * Rediscover the technologies available on this tag. |
| 291 | * <p> |
| 292 | * The technologies that are available on a tag may change due to |
| 293 | * operations being performed on a tag. For example, formatting a |
| 294 | * tag as NDEF adds the {@link Ndef} technology. The {@link rediscover} |
| 295 | * method reenumerates the available technologies on the tag |
| 296 | * and returns a new {@link Tag} object containing these technologies. |
| 297 | * <p> |
| 298 | * You may not be connected to any of this {@link Tag}'s technologies |
| 299 | * when calling this method. |
| 300 | * This method guarantees that you will be returned the same Tag |
| 301 | * if it is still in the field. |
| 302 | * <p>May cause RF activity and may block. Must not be called |
| 303 | * from the main application thread. A blocked call will be canceled with |
| 304 | * {@link IOException} by calling {@link #close} from another thread. |
| 305 | * <p>Does not remove power from the RF field, so a tag having a random |
| 306 | * ID should not change its ID. |
| 307 | * @return the rediscovered tag object. |
| 308 | * @throws IOException if the tag cannot be rediscovered |
| 309 | * @hide |
| 310 | */ |
| 311 | // TODO See if we need TagLostException |
| 312 | // TODO Unhide for ICS |
| 313 | // TODO Update documentation to make sure it matches with the final |
| 314 | // implementation. |
| 315 | public Tag rediscover() throws IOException { |
| 316 | if (getConnectedTechnology() != -1) { |
| 317 | throw new IllegalStateException("Close connection to the technology first!"); |
| 318 | } |
| 319 | |
Martijn Coenen | 23fc93a | 2011-11-28 10:43:14 -0800 | [diff] [blame] | 320 | if (mTagService == null) { |
| 321 | throw new IOException("Mock tags don't support this operation."); |
| 322 | } |
Martijn Coenen | 2dcae567 | 2011-06-02 16:02:00 -0700 | [diff] [blame] | 323 | try { |
| 324 | Tag newTag = mTagService.rediscover(getServiceHandle()); |
| 325 | if (newTag != null) { |
| 326 | return newTag; |
| 327 | } else { |
| 328 | throw new IOException("Failed to rediscover tag"); |
| 329 | } |
| 330 | } catch (RemoteException e) { |
| 331 | throw new IOException("NFC service dead"); |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 336 | /** @hide */ |
| 337 | public boolean hasTech(int techType) { |
| 338 | for (int tech : mTechList) { |
| 339 | if (tech == techType) return true; |
| 340 | } |
| 341 | return false; |
| 342 | } |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 343 | |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 344 | /** @hide */ |
| 345 | public Bundle getTechExtras(int tech) { |
Martijn Coenen | 1253ebc | 2010-11-24 11:13:57 +0100 | [diff] [blame] | 346 | int pos = -1; |
| 347 | for (int idx = 0; idx < mTechList.length; idx++) { |
| 348 | if (mTechList[idx] == tech) { |
| 349 | pos = idx; |
| 350 | break; |
| 351 | } |
| 352 | } |
Jeff Hamilton | 6be655c | 2010-11-12 12:28:16 -0600 | [diff] [blame] | 353 | if (pos < 0) { |
| 354 | return null; |
| 355 | } |
| 356 | |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 357 | return mTechExtras[pos]; |
| 358 | } |
Jeff Hamilton | 6be655c | 2010-11-12 12:28:16 -0600 | [diff] [blame] | 359 | |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 360 | /** @hide */ |
Mathew Inwood | 57069dc | 2018-07-31 15:33:20 +0100 | [diff] [blame] | 361 | @UnsupportedAppUsage |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 362 | public INfcTag getTagService() { |
| 363 | return mTagService; |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 364 | } |
| 365 | |
Nick Pelly | 74fe6c6 | 2011-02-02 22:37:40 -0800 | [diff] [blame] | 366 | /** |
| 367 | * Human-readable description of the tag, for debugging. |
| 368 | */ |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 369 | @Override |
| 370 | public String toString() { |
Jeff Hamilton | 8856c42 | 2011-06-30 17:35:05 -0500 | [diff] [blame] | 371 | StringBuilder sb = new StringBuilder("TAG: Tech ["); |
| 372 | String[] techList = getTechList(); |
| 373 | int length = techList.length; |
| 374 | for (int i = 0; i < length; i++) { |
| 375 | sb.append(techList[i]); |
| 376 | if (i < length - 1) { |
| 377 | sb.append(", "); |
| 378 | } |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 379 | } |
Jeff Hamilton | 8856c42 | 2011-06-30 17:35:05 -0500 | [diff] [blame] | 380 | sb.append("]"); |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 381 | return sb.toString(); |
| 382 | } |
| 383 | |
| 384 | /*package*/ static byte[] readBytesWithNull(Parcel in) { |
| 385 | int len = in.readInt(); |
| 386 | byte[] result = null; |
Sylvain Fonteneau | e2e4ea9 | 2010-10-25 07:28:03 -0700 | [diff] [blame] | 387 | if (len >= 0) { |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 388 | result = new byte[len]; |
| 389 | in.readByteArray(result); |
| 390 | } |
| 391 | return result; |
| 392 | } |
| 393 | |
| 394 | /*package*/ static void writeBytesWithNull(Parcel out, byte[] b) { |
| 395 | if (b == null) { |
| 396 | out.writeInt(-1); |
| 397 | return; |
| 398 | } |
| 399 | out.writeInt(b.length); |
| 400 | out.writeByteArray(b); |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 401 | } |
| 402 | |
| 403 | @Override |
| 404 | public int describeContents() { |
| 405 | return 0; |
| 406 | } |
| 407 | |
| 408 | @Override |
| 409 | public void writeToParcel(Parcel dest, int flags) { |
Sylvain Fonteneau | c5a418e | 2011-01-24 10:23:43 +0100 | [diff] [blame] | 410 | // Null mTagService means this is a mock tag |
| 411 | int isMock = (mTagService == null)?1:0; |
| 412 | |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 413 | writeBytesWithNull(dest, mId); |
Jeff Hamilton | 6be655c | 2010-11-12 12:28:16 -0600 | [diff] [blame] | 414 | dest.writeInt(mTechList.length); |
| 415 | dest.writeIntArray(mTechList); |
| 416 | dest.writeTypedArray(mTechExtras, 0); |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 417 | dest.writeInt(mServiceHandle); |
Sylvain Fonteneau | c5a418e | 2011-01-24 10:23:43 +0100 | [diff] [blame] | 418 | dest.writeInt(isMock); |
| 419 | if (isMock == 0) { |
| 420 | dest.writeStrongBinder(mTagService.asBinder()); |
| 421 | } |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 422 | } |
| 423 | |
| 424 | public static final Parcelable.Creator<Tag> CREATOR = |
| 425 | new Parcelable.Creator<Tag>() { |
Jeff Hamilton | 6be655c | 2010-11-12 12:28:16 -0600 | [diff] [blame] | 426 | @Override |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 427 | public Tag createFromParcel(Parcel in) { |
Sylvain Fonteneau | c5a418e | 2011-01-24 10:23:43 +0100 | [diff] [blame] | 428 | INfcTag tagService; |
| 429 | |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 430 | // Tag fields |
| 431 | byte[] id = Tag.readBytesWithNull(in); |
Jeff Hamilton | 6be655c | 2010-11-12 12:28:16 -0600 | [diff] [blame] | 432 | int[] techList = new int[in.readInt()]; |
| 433 | in.readIntArray(techList); |
| 434 | Bundle[] techExtras = in.createTypedArray(Bundle.CREATOR); |
Nick Pelly | 07f3bee | 2010-10-21 21:42:24 -0700 | [diff] [blame] | 435 | int serviceHandle = in.readInt(); |
Sylvain Fonteneau | c5a418e | 2011-01-24 10:23:43 +0100 | [diff] [blame] | 436 | int isMock = in.readInt(); |
| 437 | if (isMock == 0) { |
| 438 | tagService = INfcTag.Stub.asInterface(in.readStrongBinder()); |
| 439 | } |
| 440 | else { |
| 441 | tagService = null; |
| 442 | } |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 443 | |
Jeff Hamilton | 4e21e1d | 2011-01-21 01:13:06 -0600 | [diff] [blame] | 444 | return new Tag(id, techList, techExtras, serviceHandle, tagService); |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 445 | } |
Jeff Hamilton | 6be655c | 2010-11-12 12:28:16 -0600 | [diff] [blame] | 446 | |
| 447 | @Override |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 448 | public Tag[] newArray(int size) { |
| 449 | return new Tag[size]; |
| 450 | } |
| 451 | }; |
Martijn Coenen | 4049f9d0 | 2010-12-14 16:58:27 +0100 | [diff] [blame] | 452 | |
Jeff Hamilton | be372d6 | 2010-12-22 19:20:26 -0600 | [diff] [blame] | 453 | /** |
| 454 | * For internal use only. |
| 455 | * |
Martijn Coenen | 4049f9d0 | 2010-12-14 16:58:27 +0100 | [diff] [blame] | 456 | * @hide |
| 457 | */ |
| 458 | public synchronized void setConnectedTechnology(int technology) { |
| 459 | if (mConnectedTechnology == -1) { |
| 460 | mConnectedTechnology = technology; |
| 461 | } else { |
| 462 | throw new IllegalStateException("Close other technology first!"); |
| 463 | } |
| 464 | } |
| 465 | |
Jeff Hamilton | be372d6 | 2010-12-22 19:20:26 -0600 | [diff] [blame] | 466 | /** |
| 467 | * For internal use only. |
| 468 | * |
Martijn Coenen | 4049f9d0 | 2010-12-14 16:58:27 +0100 | [diff] [blame] | 469 | * @hide |
| 470 | */ |
| 471 | public int getConnectedTechnology() { |
| 472 | return mConnectedTechnology; |
| 473 | } |
| 474 | |
Jeff Hamilton | be372d6 | 2010-12-22 19:20:26 -0600 | [diff] [blame] | 475 | /** |
| 476 | * For internal use only. |
| 477 | * |
Martijn Coenen | 4049f9d0 | 2010-12-14 16:58:27 +0100 | [diff] [blame] | 478 | * @hide |
| 479 | */ |
| 480 | public void setTechnologyDisconnected() { |
| 481 | mConnectedTechnology = -1; |
| 482 | } |
Martijn Coenen | 1253ebc | 2010-11-24 11:13:57 +0100 | [diff] [blame] | 483 | } |