BasicTagTechnology.java revision 0d27f999f4b1ad51da11946800b40d2978fc6326
1590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly/*
2590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly * Copyright (C) 2010 The Android Open Source Project
3590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly *
4590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly * Licensed under the Apache License, Version 2.0 (the "License");
5590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly * you may not use this file except in compliance with the License.
6590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly * You may obtain a copy of the License at
7590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly *
8590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly *      http://www.apache.org/licenses/LICENSE-2.0
9590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly *
10590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly * Unless required by applicable law or agreed to in writing, software
11590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly * distributed under the License is distributed on an "AS IS" BASIS,
12590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly * See the License for the specific language governing permissions and
14590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly * limitations under the License.
15590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly */
16590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
176be655c768a82716612c00fdd156254d8dc00f42Jeff Hamiltonpackage android.nfc.technology;
18590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
19590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pellyimport java.io.IOException;
20590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
216be655c768a82716612c00fdd156254d8dc00f42Jeff Hamiltonimport android.nfc.INfcAdapter;
226be655c768a82716612c00fdd156254d8dc00f42Jeff Hamiltonimport android.nfc.INfcTag;
236be655c768a82716612c00fdd156254d8dc00f42Jeff Hamiltonimport android.nfc.NfcAdapter;
246be655c768a82716612c00fdd156254d8dc00f42Jeff Hamiltonimport android.nfc.Tag;
254049f9d00a86f848d42d2429068496b31a6795adMartijn Coenenimport android.nfc.ErrorCodes;
26590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pellyimport android.os.RemoteException;
27590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pellyimport android.util.Log;
28590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
29590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly/**
306be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton * A base class for tag technologies that are built on top of transceive().
31590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly */
326be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton/* package */ abstract class BasicTagTechnology implements TagTechnology {
33590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
34590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    /*package*/ final Tag mTag;
35590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    /*package*/ boolean mIsConnected;
366be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton    /*package*/ int mSelectedTechnology;
376d55e1342fc35c26dd97700ae791b34668266018Nick Pelly    private final NfcAdapter mAdapter;
386d55e1342fc35c26dd97700ae791b34668266018Nick Pelly
396d55e1342fc35c26dd97700ae791b34668266018Nick Pelly    // Following fields are final after construction, except for
406d55e1342fc35c26dd97700ae791b34668266018Nick Pelly    // during attemptDeadServiceRecovery() when NFC crashes.
416d55e1342fc35c26dd97700ae791b34668266018Nick Pelly    // Not locked - we accept a best effort attempt when NFC crashes.
426d55e1342fc35c26dd97700ae791b34668266018Nick Pelly    /*package*/ INfcAdapter mService;
436d55e1342fc35c26dd97700ae791b34668266018Nick Pelly    /*package*/ INfcTag mTagService;
44590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
45590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    private static final String TAG = "NFC";
46590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
476be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton    /**
486be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton     * @hide
496be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton     */
506be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton    public BasicTagTechnology(NfcAdapter adapter, Tag tag, int tech) throws RemoteException {
516be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton        int[] techList = tag.getTechnologyList();
52a926540d5455a973dd8ca19c00c108620d9c68c2Sylvain Fonteneau        int i;
53a926540d5455a973dd8ca19c00c108620d9c68c2Sylvain Fonteneau
54a926540d5455a973dd8ca19c00c108620d9c68c2Sylvain Fonteneau        // Check target validity
556be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton        for (i = 0; i < techList.length; i++) {
566be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton            if (tech == techList[i]) {
57a926540d5455a973dd8ca19c00c108620d9c68c2Sylvain Fonteneau                break;
58a926540d5455a973dd8ca19c00c108620d9c68c2Sylvain Fonteneau            }
59a926540d5455a973dd8ca19c00c108620d9c68c2Sylvain Fonteneau        }
606be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton        if (i >= techList.length) {
616be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton            // Technology not found
626be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton            throw new IllegalArgumentException("Technology " + tech + " not present on tag " + tag);
63a926540d5455a973dd8ca19c00c108620d9c68c2Sylvain Fonteneau        }
64a926540d5455a973dd8ca19c00c108620d9c68c2Sylvain Fonteneau
656d55e1342fc35c26dd97700ae791b34668266018Nick Pelly        mAdapter = adapter;
666be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton        mService = mAdapter.getService();
671253ebc74a8453a88dc47a2b698145098d201681Martijn Coenen        try {
681253ebc74a8453a88dc47a2b698145098d201681Martijn Coenen          mTagService = mService.getNfcTagInterface();
691253ebc74a8453a88dc47a2b698145098d201681Martijn Coenen        } catch (RemoteException e) {
701253ebc74a8453a88dc47a2b698145098d201681Martijn Coenen            attemptDeadServiceRecovery(e);
711253ebc74a8453a88dc47a2b698145098d201681Martijn Coenen        }
72590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        mTag = tag;
736be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton        mSelectedTechnology = tech;
74a926540d5455a973dd8ca19c00c108620d9c68c2Sylvain Fonteneau    }
75a926540d5455a973dd8ca19c00c108620d9c68c2Sylvain Fonteneau
766be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton    /**
776be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton     * @hide
786be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton     */
796be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton    public BasicTagTechnology(NfcAdapter adapter, Tag tag) throws RemoteException {
806be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton        this(adapter, tag, tag.getTechnologyList()[0]);
816d55e1342fc35c26dd97700ae791b34668266018Nick Pelly    }
826d55e1342fc35c26dd97700ae791b34668266018Nick Pelly
836d55e1342fc35c26dd97700ae791b34668266018Nick Pelly    /** NFC service dead - attempt best effort recovery */
846d55e1342fc35c26dd97700ae791b34668266018Nick Pelly    /*package*/ void attemptDeadServiceRecovery(Exception e) {
856d55e1342fc35c26dd97700ae791b34668266018Nick Pelly        mAdapter.attemptDeadServiceRecovery(e);
866d55e1342fc35c26dd97700ae791b34668266018Nick Pelly        /* assigning to mService is not thread-safe, but this is best-effort code
876d55e1342fc35c26dd97700ae791b34668266018Nick Pelly         * and on a well-behaved system should never happen */
886be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton        mService = mAdapter.getService();
896d55e1342fc35c26dd97700ae791b34668266018Nick Pelly        try {
906d55e1342fc35c26dd97700ae791b34668266018Nick Pelly            mTagService = mService.getNfcTagInterface();
916d55e1342fc35c26dd97700ae791b34668266018Nick Pelly        } catch (RemoteException e2) {
926d55e1342fc35c26dd97700ae791b34668266018Nick Pelly            Log.e(TAG, "second RemoteException trying to recover from dead NFC service", e2);
936d55e1342fc35c26dd97700ae791b34668266018Nick Pelly        }
94590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    }
95590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
96590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    /**
97c9f7890a203a013646650a695157277df81b6a17Scott Main     * Get the {@link Tag} this connection is associated with.
98e47150e933e6f610546f57183477f324566e521eNick Pelly     * <p>Requires {@link android.Manifest.permission#NFC} permission.
99590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     */
1006be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton    @Override
101590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    public Tag getTag() {
102590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        return mTag;
103590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    }
104590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
1054049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen    public void checkConnected() {
1064049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen       if ((mTag.getConnectedTechnology() != getTechnologyId()) ||
1074049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen               (mTag.getConnectedTechnology() == -1)) {
1084049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen           throw new IllegalStateException("Call connect() first!");
1094049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen       }
1104049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen    }
1114049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen
112e47150e933e6f610546f57183477f324566e521eNick Pelly    /**
113e47150e933e6f610546f57183477f324566e521eNick Pelly     * <p>Requires {@link android.Manifest.permission#NFC} permission.
114e47150e933e6f610546f57183477f324566e521eNick Pelly     */
1156be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton    @Override
1166be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton    public int getTechnologyId() {
1176be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton        return mSelectedTechnology;
118590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    }
119590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
120590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    /**
121c9f7890a203a013646650a695157277df81b6a17Scott Main     * Helper to indicate if {@link #transceive transceive()} calls might succeed.
122590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     * <p>
123590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     * Does not cause RF activity, and does not block.
124e47150e933e6f610546f57183477f324566e521eNick Pelly     * <p>Requires {@link android.Manifest.permission#NFC} permission.
125c9f7890a203a013646650a695157277df81b6a17Scott Main     * @return true if {@link #connect} has completed successfully and the {@link Tag} is believed
126c9f7890a203a013646650a695157277df81b6a17Scott Main     * to be within range. Applications must still handle {@link java.io.IOException}
127c9f7890a203a013646650a695157277df81b6a17Scott Main     * while using {@link #transceive transceive()}, in case connection is lost after this method
128c9f7890a203a013646650a695157277df81b6a17Scott Main     * returns true.
129590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     */
130590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    public boolean isConnected() {
131a71354d76689802152c33af257092d639c03c421Sylvain Fonteneau        if (!mIsConnected) {
132a71354d76689802152c33af257092d639c03c421Sylvain Fonteneau            return false;
133a71354d76689802152c33af257092d639c03c421Sylvain Fonteneau        }
134a71354d76689802152c33af257092d639c03c421Sylvain Fonteneau
135a71354d76689802152c33af257092d639c03c421Sylvain Fonteneau        try {
1366be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton            return mTagService.isPresent(mTag.getServiceHandle());
137a71354d76689802152c33af257092d639c03c421Sylvain Fonteneau        } catch (RemoteException e) {
1386d55e1342fc35c26dd97700ae791b34668266018Nick Pelly            attemptDeadServiceRecovery(e);
139a71354d76689802152c33af257092d639c03c421Sylvain Fonteneau            return false;
140a71354d76689802152c33af257092d639c03c421Sylvain Fonteneau        }
141590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    }
142590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
143590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    /**
144c9f7890a203a013646650a695157277df81b6a17Scott Main     * Connect to the {@link Tag} associated with this connection.
145590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     * <p>
146590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     * This method blocks until the connection is established.
147590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     * <p>
148c9f7890a203a013646650a695157277df81b6a17Scott Main     * {@link #close} can be called from another thread to cancel this connection
149590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     * attempt.
150e47150e933e6f610546f57183477f324566e521eNick Pelly     * <p>Requires {@link android.Manifest.permission#NFC} permission.
151590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     * @throws IOException if the target is lost, or connect canceled
152590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     */
1536be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton    @Override
154590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    public void connect() throws IOException {
1554049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen        try {
1564049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen            int errorCode = mTagService.connect(mTag.getServiceHandle(), getTechnologyId());
1574049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen
1584049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen            if (errorCode == ErrorCodes.SUCCESS) {
1594049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen                // Store this in the tag object
1604049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen                mTag.setConnectedTechnology(getTechnologyId());
1614049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen                mIsConnected = true;
1624049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen            } else {
1634049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen                throw new IOException();
1644049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen            }
1654049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen        } catch (RemoteException e) {
1664049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen            attemptDeadServiceRecovery(e);
1670d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen            throw new IOException("NFC service died");
1680d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen        }
1690d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen    }
1700d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen
1710d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen    /**
1720d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen     * Re-connect to the {@link Tag} associated with this connection.
1730d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen     * <p>
1740d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen     * Reconnecting to a tag can be used to reset the state of the tag itself.
1750d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen     * This method blocks until the connection is re-established.
1760d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen     * <p>
1770d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen     * {@link #close} can be called from another thread to cancel this connection
1780d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen     * attempt.
1790d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen     * <p>Requires {@link android.Manifest.permission#NFC} permission.
1800d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen     * @throws IOException if the target is lost, or connect canceled
1810d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen     */
1820d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen    @Override
1830d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen    public void reconnect() throws IOException {
1840d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen        if (!mIsConnected) {
1850d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen            throw new IllegalStateException("Technology not connected yet");
1860d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen        } else {
1870d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen            try {
1880d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen                int errorCode = mTagService.reconnect(mTag.getServiceHandle());
1890d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen
1900d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen                if (errorCode != ErrorCodes.SUCCESS) {
1910d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen                    mIsConnected = false;
1920d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen                    mTag.setTechnologyDisconnected();
1930d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen                    throw new IOException();
1940d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen                }
1950d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen            } catch (RemoteException e) {
1960d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen                mIsConnected = false;
1970d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen                mTag.setTechnologyDisconnected();
1980d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen                attemptDeadServiceRecovery(e);
1990d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen                throw new IOException("NFC service died");
2000d27f999f4b1ad51da11946800b40d2978fc6326Martijn Coenen            }
2014049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen        }
202590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    }
203590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
204590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    /**
205c9f7890a203a013646650a695157277df81b6a17Scott Main     * Close this connection.
206590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     * <p>
207c9f7890a203a013646650a695157277df81b6a17Scott Main     * Causes blocking operations such as {@link #transceive transceive()} or {@link #connect} to
208c9f7890a203a013646650a695157277df81b6a17Scott Main     * be canceled and immediately throw {@link java.io.IOException}.
209590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     * <p>
210c9f7890a203a013646650a695157277df81b6a17Scott Main     * Once this method is called, this object cannot be re-used and should be discarded. Further
211c9f7890a203a013646650a695157277df81b6a17Scott Main     * calls to {@link #transceive transceive()} or {@link #connect} will fail.
212e47150e933e6f610546f57183477f324566e521eNick Pelly     * <p>Requires {@link android.Manifest.permission#NFC} permission.
213590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     */
2146be655c768a82716612c00fdd156254d8dc00f42Jeff Hamilton    @Override
215590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    public void close() {
216590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        try {
217b79173f6602359d00a1a89f4d6505a44d461d796Martijn Coenen            /* Note that we don't want to physically disconnect the tag,
218b79173f6602359d00a1a89f4d6505a44d461d796Martijn Coenen             * but just reconnect to it to reset its state
219b79173f6602359d00a1a89f4d6505a44d461d796Martijn Coenen             */
220b79173f6602359d00a1a89f4d6505a44d461d796Martijn Coenen            mTagService.reconnect(mTag.getServiceHandle());
221590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        } catch (RemoteException e) {
2226d55e1342fc35c26dd97700ae791b34668266018Nick Pelly            attemptDeadServiceRecovery(e);
2234049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen        } finally {
2244049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen            mIsConnected = false;
2254049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen            mTag.setTechnologyDisconnected();
226590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        }
227590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    }
228590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
229590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    /**
230c9f7890a203a013646650a695157277df81b6a17Scott Main     * Send data to a tag and receive the response.
231590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     * <p>
232590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     * This method will block until the response is received. It can be canceled
233c9f7890a203a013646650a695157277df81b6a17Scott Main     * with {@link #close}.
234e47150e933e6f610546f57183477f324566e521eNick Pelly     * <p>Requires {@link android.Manifest.permission#NFC} permission.
235590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     *
236590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     * @param data bytes to send
237590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     * @return bytes received in response
238590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     * @throws IOException if the target is lost or connection closed
239590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     */
240590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    public byte[] transceive(byte[] data) throws IOException {
2414049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen        checkConnected();
2424049f9d00a86f848d42d2429068496b31a6795adMartijn Coenen
243590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        try {
244fc5a3b6cfb85679e82a39730c7154b55b0711a0cMartijn Coenen            byte[] response = mTagService.transceive(mTag.getServiceHandle(), data, true);
245590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            if (response == null) {
246fc5a3b6cfb85679e82a39730c7154b55b0711a0cMartijn Coenen                throw new IOException("transceive failed");
247590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            }
248590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            return response;
249590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        } catch (RemoteException e) {
2506d55e1342fc35c26dd97700ae791b34668266018Nick Pelly            attemptDeadServiceRecovery(e);
251590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            throw new IOException("NFC service died");
252590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        }
253590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    }
254590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly}
255