summaryrefslogtreecommitdiffstats
path: root/core/java/android/nfc/RawTagConnection.java
blob: 37d700ca6709054596c137b72e71a41f2c626559 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.nfc;

import java.io.IOException;

import android.os.RemoteException;
import android.util.Log;

/**
 * A low-level connection to a {@link Tag} target.
 * <p>You can acquire this kind of connection with {@link NfcAdapter#createRawTagConnection
 * createRawTagConnection()}. Use the connection to send and receive data with {@link #transceive
 * transceive()}.
 * <p>
 * Applications must implement their own protocol stack on top of {@link #transceive transceive()}.
 *
 * <p class="note"><strong>Note:</strong>
 * Most methods require the TODO
 * permission.
 */
public class RawTagConnection {

    /*package*/ final INfcAdapter mService;
    /*package*/ final INfcTag mTagService;
    /*package*/ final Tag mTag;
    /*package*/ boolean mIsConnected;
    /*package*/ String mSelectedTarget;

    private static final String TAG = "NFC";

    /* package private */ RawTagConnection(INfcAdapter service, Tag tag, String target) throws RemoteException {
        String[] targets = tag.getRawTargets();
        int i;

        // Check target validity
        for (i=0;i<targets.length;i++) {
            if (target.equals(targets[i])) {
                break;
            }
        }
        if (i >= targets.length) {
            // Target not found
            throw new IllegalArgumentException();
        }

        mService = service;
        mTagService = service.getNfcTagInterface();
        mService.openTagConnection(tag);  // TODO(nxp): don't connect until connect()
        mTag = tag;
        mSelectedTarget = target;
    }

    /* package private */ RawTagConnection(INfcAdapter service, Tag tag) throws RemoteException {
        this(service, tag, tag.getRawTargets()[0]);
    }

    /**
     * Get the {@link Tag} this connection is associated with.
     */
    public Tag getTag() {
        return mTag;
    }

    public String getTagTarget() {
        return mSelectedTarget;
    }

    /**
     * Helper to indicate if {@link #transceive transceive()} calls might succeed.
     * <p>
     * Does not cause RF activity, and does not block.
     * <p>
     * @return true if {@link #connect} has completed successfully and the {@link Tag} is believed
     * to be within range. Applications must still handle {@link java.io.IOException}
     * while using {@link #transceive transceive()}, in case connection is lost after this method
     * returns true.
     */
    public boolean isConnected() {
        // TODO(nxp): update mIsConnected when tag goes out of range -
        //            but do not do an active prescence check in
        //            isConnected()
        return mIsConnected;
    }

    /**
     * Connect to the {@link Tag} associated with this connection.
     * <p>
     * This method blocks until the connection is established.
     * <p>
     * {@link #close} can be called from another thread to cancel this connection
     * attempt.
     *
     * @throws IOException if the target is lost, or connect canceled
     */
    public void connect() throws IOException {
        //TODO(nxp): enforce exclusivity
        mIsConnected = true;
    }

    /**
     * Close this connection.
     * <p>
     * Causes blocking operations such as {@link #transceive transceive()} or {@link #connect} to
     * be canceled and immediately throw {@link java.io.IOException}.
     * <p>
     * Once this method is called, this object cannot be re-used and should be discarded. Further
     * calls to {@link #transceive transceive()} or {@link #connect} will fail.
     */
    public void close() {
        mIsConnected = false;
        try {
            mTagService.close(mTag.mNativeHandle);
        } catch (RemoteException e) {
            Log.e(TAG, "NFC service died", e);
        }
    }

    /**
     * Send data to a tag and receive the response.
     * <p>
     * This method will block until the response is received. It can be canceled
     * with {@link #close}.
     * <p>
     * Requires NFC_WRITE permission.
     *
     * @param data bytes to send
     * @return bytes received in response
     * @throws IOException if the target is lost or connection closed
     */
    public byte[] transceive(byte[] data) throws IOException {
        try {
            byte[] response = mTagService.transceive(mTag.mNativeHandle, data);
            if (response == null) {
                throw new IOException("transcieve failed");
            }
            return response;
        } catch (RemoteException e) {
            Log.e(TAG, "NFC service died", e);
            throw new IOException("NFC service died");
        }
    }
}