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.tech;
18 
19 import android.nfc.ErrorCodes;
20 import android.nfc.Tag;
21 import android.nfc.TransceiveResult;
22 import android.os.RemoteException;
23 import android.util.Log;
24 
25 import java.io.IOException;
26 
27 /**
28  * A base class for tag technologies that are built on top of transceive().
29  */
30 abstract class BasicTagTechnology implements TagTechnology {
31     private static final String TAG = "NFC";
32 
33     final Tag mTag;
34 
35     boolean mIsConnected;
36     int mSelectedTechnology;
37 
BasicTagTechnology(Tag tag, int tech)38     BasicTagTechnology(Tag tag, int tech) throws RemoteException {
39         mTag = tag;
40         mSelectedTechnology = tech;
41     }
42 
43     @Override
getTag()44     public Tag getTag() {
45         return mTag;
46     }
47 
48     /** Internal helper to throw IllegalStateException if the technology isn't connected */
checkConnected()49     void checkConnected() {
50        if ((mTag.getConnectedTechnology() != mSelectedTechnology) ||
51                (mTag.getConnectedTechnology() == -1)) {
52            throw new IllegalStateException("Call connect() first!");
53        }
54     }
55 
56     @Override
isConnected()57     public boolean isConnected() {
58         if (!mIsConnected) {
59             return false;
60         }
61 
62         try {
63             return mTag.getTagService().isPresent(mTag.getServiceHandle());
64         } catch (RemoteException e) {
65             Log.e(TAG, "NFC service dead", e);
66             return false;
67         }
68     }
69 
70     @Override
connect()71     public void connect() throws IOException {
72         try {
73             int errorCode = mTag.getTagService().connect(mTag.getServiceHandle(),
74                     mSelectedTechnology);
75 
76             if (errorCode == ErrorCodes.SUCCESS) {
77                 // Store this in the tag object
78                 if (!mTag.setConnectedTechnology(mSelectedTechnology)) {
79                     Log.e(TAG, "Close other technology first!");
80                     throw new IOException("Only one TagTechnology can be connected at a time.");
81                 }
82                 mIsConnected = true;
83             } else if (errorCode == ErrorCodes.ERROR_NOT_SUPPORTED) {
84                 throw new UnsupportedOperationException("Connecting to " +
85                         "this technology is not supported by the NFC " +
86                         "adapter.");
87             } else {
88                 throw new IOException();
89             }
90         } catch (RemoteException e) {
91             Log.e(TAG, "NFC service dead", e);
92             throw new IOException("NFC service died");
93         }
94     }
95 
96     /** @hide */
97     @Override
reconnect()98     public void reconnect() throws IOException {
99         if (!mIsConnected) {
100             throw new IllegalStateException("Technology not connected yet");
101         }
102 
103         try {
104             int errorCode = mTag.getTagService().reconnect(mTag.getServiceHandle());
105 
106             if (errorCode != ErrorCodes.SUCCESS) {
107                 mIsConnected = false;
108                 mTag.setTechnologyDisconnected();
109                 throw new IOException();
110             }
111         } catch (RemoteException e) {
112             mIsConnected = false;
113             mTag.setTechnologyDisconnected();
114             Log.e(TAG, "NFC service dead", e);
115             throw new IOException("NFC service died");
116         }
117     }
118 
119     @Override
close()120     public void close() throws IOException {
121         try {
122             /* Note that we don't want to physically disconnect the tag,
123              * but just reconnect to it to reset its state
124              */
125             mTag.getTagService().resetTimeouts();
126             mTag.getTagService().reconnect(mTag.getServiceHandle());
127         } catch (RemoteException e) {
128             Log.e(TAG, "NFC service dead", e);
129         } finally {
130             mIsConnected = false;
131             mTag.setTechnologyDisconnected();
132         }
133     }
134 
135     /** Internal getMaxTransceiveLength() */
getMaxTransceiveLengthInternal()136     int getMaxTransceiveLengthInternal() {
137         try {
138             return mTag.getTagService().getMaxTransceiveLength(mSelectedTechnology);
139         } catch (RemoteException e) {
140             Log.e(TAG, "NFC service dead", e);
141             return 0;
142         }
143     }
144     /** Internal transceive */
transceive(byte[] data, boolean raw)145     byte[] transceive(byte[] data, boolean raw) throws IOException {
146         checkConnected();
147 
148         try {
149             TransceiveResult result = mTag.getTagService().transceive(mTag.getServiceHandle(),
150                     data, raw);
151             if (result == null) {
152                 throw new IOException("transceive failed");
153             } else {
154                 return result.getResponseOrThrow();
155             }
156         } catch (RemoteException e) {
157             Log.e(TAG, "NFC service dead", e);
158             throw new IOException("NFC service died");
159         }
160     }
161 }
162