blob: fd7cb33b2db19a25ed74c5bbc21df917d0ba5174 [file] [log] [blame]
Nick Pelly367f41f2011-03-08 11:43:30 -08001/*
2 * Copyright (C) 2011 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 com.android.nfc_extras;
18
Nick Pelly367f41f2011-03-08 11:43:30 -080019import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
Nick Pelly367f41f2011-03-08 11:43:30 -080021import android.os.Binder;
22import android.os.Bundle;
Nick Pelly367f41f2011-03-08 11:43:30 -080023import android.os.RemoteException;
24
Jeff Hamiltonbb951c82011-11-08 16:55:13 -060025import java.io.IOException;
26
Nick Pelly367f41f2011-03-08 11:43:30 -080027public class NfcExecutionEnvironment {
Nick Pellycc9ee722011-04-26 16:38:00 -070028 private final NfcAdapterExtras mExtras;
Jeff Hamiltonbb951c82011-11-08 16:55:13 -060029 private final Binder mToken;
Nick Pelly367f41f2011-03-08 11:43:30 -080030
Martijn Coenendd6b9592013-02-11 12:47:32 -080031 // Exception types that can be thrown by NfcService
32 // 1:1 mapped to EE_ERROR_ types in NfcService
33 private static final int EE_ERROR_IO = -1;
34 private static final int EE_ERROR_ALREADY_OPEN = -2;
35 private static final int EE_ERROR_INIT = -3;
36 private static final int EE_ERROR_LISTEN_MODE = -4;
37 private static final int EE_ERROR_EXT_FIELD = -5;
38 private static final int EE_ERROR_NFC_DISABLED = -6;
39
Nick Pelly367f41f2011-03-08 11:43:30 -080040 /**
41 * Broadcast Action: An ISO-DEP AID was selected.
42 *
43 * <p>This happens as the result of a 'SELECT AID' command from an
44 * external NFC reader/writer.
45 *
46 * <p>Always contains the extra field {@link #EXTRA_AID}
47 *
48 * <p class="note">
49 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission
50 * to receive.
51 */
52 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
53 public static final String ACTION_AID_SELECTED =
54 "com.android.nfc_extras.action.AID_SELECTED";
55
56 /**
57 * Mandatory byte array extra field in {@link #ACTION_AID_SELECTED}.
58 *
59 * <p>Contains the AID selected.
60 * @hide
61 */
62 public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID";
63
mike wakerly2f9ad8b2011-06-27 17:29:30 -070064 /**
65 * Broadcast action: A filtered APDU was received.
66 *
67 * <p>This happens when an APDU of interest was matched by the Nfc adapter,
68 * for instance as the result of matching an externally-configured filter.
69 *
70 * <p>The filter configuration mechanism is not currently defined.
71 *
72 * <p>Always contains the extra field {@link EXTRA_APDU_BYTES}.
73 *
74 * @hide
75 */
76 public static final String ACTION_APDU_RECEIVED =
77 "com.android.nfc_extras.action.APDU_RECEIVED";
78
79 /**
80 * Mandatory byte array extra field in {@link #ACTION_APDU_RECEIVED}.
81 *
82 * <p>Contains the bytes of the received APDU.
83 *
84 * @hide
85 */
86 public static final String EXTRA_APDU_BYTES =
87 "com.android.nfc_extras.extra.APDU_BYTES";
88
89 /**
90 * Broadcast action: An EMV card removal event was detected.
91 *
92 * @hide
93 */
94 public static final String ACTION_EMV_CARD_REMOVAL =
95 "com.android.nfc_extras.action.EMV_CARD_REMOVAL";
96
97 /**
98 * Broadcast action: An adapter implementing MIFARE Classic via card
99 * emulation detected that a block has been accessed.
100 *
101 * <p>This may only be issued for the first block that the reader
102 * authenticates to.
103 *
104 * <p>May contain the extra field {@link #EXTRA_MIFARE_BLOCK}.
105 *
106 * @hide
107 */
108 public static final String ACTION_MIFARE_ACCESS_DETECTED =
109 "com.android.nfc_extras.action.MIFARE_ACCESS_DETECTED";
110
111 /**
112 * Optional integer extra field in {@link #ACTION_MIFARE_ACCESS_DETECTED}.
113 *
114 * <p>Provides the block number being accessed. If not set, the block
115 * number being accessed is unknown.
116 *
117 * @hide
118 */
119 public static final String EXTRA_MIFARE_BLOCK =
120 "com.android.nfc_extras.extra.MIFARE_BLOCK";
121
Nick Pellycc9ee722011-04-26 16:38:00 -0700122 NfcExecutionEnvironment(NfcAdapterExtras extras) {
123 mExtras = extras;
Jeff Hamiltonbb951c82011-11-08 16:55:13 -0600124 mToken = new Binder();
Nick Pelly367f41f2011-03-08 11:43:30 -0800125 }
126
127 /**
128 * Open the NFC Execution Environment on its contact interface.
129 *
Martijn Coenendd6b9592013-02-11 12:47:32 -0800130 * <p>Opening a channel to the the secure element may fail
131 * for a number of reasons:
132 * <ul>
133 * <li>NFC must be enabled for the connection to the SE to be opened.
134 * If it is disabled at the time of this call, an {@link EeNfcDisabledException}
135 * is thrown.
Nick Pelly367f41f2011-03-08 11:43:30 -0800136 *
Martijn Coenendd6b9592013-02-11 12:47:32 -0800137 * <li>Only one process may open the secure element at a time. Additionally,
138 * this method is not reentrant. If the secure element is already opened,
139 * either by this process or by a different process, an {@link EeAlreadyOpenException}
140 * is thrown.
141 *
142 * <li>If the connection to the secure element could not be initialized,
143 * an {@link EeInitializationException} is thrown.
144 *
145 * <li>If the secure element or the NFC controller is activated in listen
146 * mode - that is, it is talking over the contactless interface - an
147 * {@link EeListenModeException} is thrown.
148 *
149 * <li>If the NFC controller is in a field powered by a remote device,
150 * such as a payment terminal, an {@link EeExternalFieldException} is
151 * thrown.
152 * </ul>
Nick Pelly367f41f2011-03-08 11:43:30 -0800153 * <p>All other NFC functionality is disabled while the NFC-EE is open
154 * on its contact interface, so make sure to call {@link #close} once complete.
155 *
156 * <p class="note">
157 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
158 *
Martijn Coenendd6b9592013-02-11 12:47:32 -0800159 * @throws EeAlreadyOpenException if the NFC-EE is already open
160 * @throws EeNfcDisabledException if NFC is disabled
161 * @throws EeInitializationException if the Secure Element could not be initialized
162 * @throws EeListenModeException if the NFCC or Secure Element is activated in listen mode
163 * @throws EeExternalFieldException if the NFCC is in the presence of a remote-powered field
164 * @throws EeIoException if an unknown error occurs
Nick Pelly367f41f2011-03-08 11:43:30 -0800165 */
Martijn Coenendd6b9592013-02-11 12:47:32 -0800166 public void open() throws EeIOException {
Nick Pelly367f41f2011-03-08 11:43:30 -0800167 try {
Jeff Hamiltonbb951c82011-11-08 16:55:13 -0600168 Bundle b = mExtras.getService().open(mExtras.mPackageName, mToken);
Nick Pelly367f41f2011-03-08 11:43:30 -0800169 throwBundle(b);
170 } catch (RemoteException e) {
Nick Pellycc9ee722011-04-26 16:38:00 -0700171 mExtras.attemptDeadServiceRecovery(e);
Martijn Coenendd6b9592013-02-11 12:47:32 -0800172 throw new EeIOException("NFC Service was dead, try again");
Nick Pelly367f41f2011-03-08 11:43:30 -0800173 }
174 }
175
176 /**
177 * Close the NFC Execution Environment on its contact interface.
178 *
179 * <p class="note">
180 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
181 *
182 * @throws IOException if the NFC-EE is already open, or some other error occurs
183 */
184 public void close() throws IOException {
185 try {
Jeff Hamiltonbb951c82011-11-08 16:55:13 -0600186 throwBundle(mExtras.getService().close(mExtras.mPackageName, mToken));
Nick Pelly367f41f2011-03-08 11:43:30 -0800187 } catch (RemoteException e) {
Nick Pellycc9ee722011-04-26 16:38:00 -0700188 mExtras.attemptDeadServiceRecovery(e);
189 throw new IOException("NFC Service was dead");
Nick Pelly367f41f2011-03-08 11:43:30 -0800190 }
191 }
192
193 /**
194 * Send raw commands to the NFC-EE and receive the response.
195 *
196 * <p class="note">
197 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
198 *
199 * @throws IOException if the NFC-EE is not open, or some other error occurs
200 */
201 public byte[] transceive(byte[] in) throws IOException {
202 Bundle b;
203 try {
Jeff Hamiltonbb951c82011-11-08 16:55:13 -0600204 b = mExtras.getService().transceive(mExtras.mPackageName, in);
Nick Pelly367f41f2011-03-08 11:43:30 -0800205 } catch (RemoteException e) {
Nick Pellycc9ee722011-04-26 16:38:00 -0700206 mExtras.attemptDeadServiceRecovery(e);
207 throw new IOException("NFC Service was dead, need to re-open");
Nick Pelly367f41f2011-03-08 11:43:30 -0800208 }
209 throwBundle(b);
210 return b.getByteArray("out");
211 }
212
Martijn Coenendd6b9592013-02-11 12:47:32 -0800213 private static void throwBundle(Bundle b) throws EeIOException {
214 switch (b.getInt("e")) {
215 case EE_ERROR_NFC_DISABLED:
216 throw new EeNfcDisabledException(b.getString("m"));
217 case EE_ERROR_IO:
218 throw new EeIOException(b.getString("m"));
219 case EE_ERROR_INIT:
220 throw new EeInitializationException(b.getString("m"));
221 case EE_ERROR_EXT_FIELD:
222 throw new EeExternalFieldException(b.getString("m"));
223 case EE_ERROR_LISTEN_MODE:
224 throw new EeListenModeException(b.getString("m"));
225 case EE_ERROR_ALREADY_OPEN:
226 throw new EeAlreadyOpenException(b.getString("m"));
Nick Pelly367f41f2011-03-08 11:43:30 -0800227 }
228 }
229}