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