1/* 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 19import java.io.IOException; 20 21import android.annotation.SdkConstant; 22import android.annotation.SdkConstant.SdkConstantType; 23import android.content.Context; 24import android.nfc.INfcAdapterExtras; 25import android.nfc.NfcAdapter; 26import android.os.Binder; 27import android.os.Bundle; 28import android.os.IBinder; 29import android.os.RemoteException; 30 31public class NfcExecutionEnvironment { 32 private final NfcAdapterExtras mExtras; 33 34 /** 35 * Broadcast Action: An ISO-DEP AID was selected. 36 * 37 * <p>This happens as the result of a 'SELECT AID' command from an 38 * external NFC reader/writer. 39 * 40 * <p>Always contains the extra field {@link #EXTRA_AID} 41 * 42 * <p class="note"> 43 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission 44 * to receive. 45 */ 46 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 47 public static final String ACTION_AID_SELECTED = 48 "com.android.nfc_extras.action.AID_SELECTED"; 49 50 /** 51 * Mandatory byte array extra field in {@link #ACTION_AID_SELECTED}. 52 * 53 * <p>Contains the AID selected. 54 * @hide 55 */ 56 public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID"; 57 58 /** 59 * Broadcast action: A filtered APDU was received. 60 * 61 * <p>This happens when an APDU of interest was matched by the Nfc adapter, 62 * for instance as the result of matching an externally-configured filter. 63 * 64 * <p>The filter configuration mechanism is not currently defined. 65 * 66 * <p>Always contains the extra field {@link EXTRA_APDU_BYTES}. 67 * 68 * @hide 69 */ 70 public static final String ACTION_APDU_RECEIVED = 71 "com.android.nfc_extras.action.APDU_RECEIVED"; 72 73 /** 74 * Mandatory byte array extra field in {@link #ACTION_APDU_RECEIVED}. 75 * 76 * <p>Contains the bytes of the received APDU. 77 * 78 * @hide 79 */ 80 public static final String EXTRA_APDU_BYTES = 81 "com.android.nfc_extras.extra.APDU_BYTES"; 82 83 /** 84 * Broadcast action: An EMV card removal event was detected. 85 * 86 * @hide 87 */ 88 public static final String ACTION_EMV_CARD_REMOVAL = 89 "com.android.nfc_extras.action.EMV_CARD_REMOVAL"; 90 91 /** 92 * Broadcast action: An adapter implementing MIFARE Classic via card 93 * emulation detected that a block has been accessed. 94 * 95 * <p>This may only be issued for the first block that the reader 96 * authenticates to. 97 * 98 * <p>May contain the extra field {@link #EXTRA_MIFARE_BLOCK}. 99 * 100 * @hide 101 */ 102 public static final String ACTION_MIFARE_ACCESS_DETECTED = 103 "com.android.nfc_extras.action.MIFARE_ACCESS_DETECTED"; 104 105 /** 106 * Optional integer extra field in {@link #ACTION_MIFARE_ACCESS_DETECTED}. 107 * 108 * <p>Provides the block number being accessed. If not set, the block 109 * number being accessed is unknown. 110 * 111 * @hide 112 */ 113 public static final String EXTRA_MIFARE_BLOCK = 114 "com.android.nfc_extras.extra.MIFARE_BLOCK"; 115 116 NfcExecutionEnvironment(NfcAdapterExtras extras) { 117 mExtras = extras; 118 } 119 120 /** 121 * Open the NFC Execution Environment on its contact interface. 122 * 123 * <p>Only one process may open the secure element at a time. If it is 124 * already open, an {@link IOException} is thrown. 125 * 126 * <p>All other NFC functionality is disabled while the NFC-EE is open 127 * on its contact interface, so make sure to call {@link #close} once complete. 128 * 129 * <p class="note"> 130 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission. 131 * 132 * @throws IOException if the NFC-EE is already open, or some other error occurs 133 */ 134 public void open() throws IOException { 135 try { 136 Bundle b = mExtras.getService().open(new Binder()); 137 throwBundle(b); 138 } catch (RemoteException e) { 139 mExtras.attemptDeadServiceRecovery(e); 140 throw new IOException("NFC Service was dead, try again"); 141 } 142 } 143 144 /** 145 * Close the NFC Execution Environment on its contact interface. 146 * 147 * <p class="note"> 148 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission. 149 * 150 * @throws IOException if the NFC-EE is already open, or some other error occurs 151 */ 152 public void close() throws IOException { 153 try { 154 throwBundle(mExtras.getService().close()); 155 } catch (RemoteException e) { 156 mExtras.attemptDeadServiceRecovery(e); 157 throw new IOException("NFC Service was dead"); 158 } 159 } 160 161 /** 162 * Send raw commands to the NFC-EE and receive the response. 163 * 164 * <p class="note"> 165 * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission. 166 * 167 * @throws IOException if the NFC-EE is not open, or some other error occurs 168 */ 169 public byte[] transceive(byte[] in) throws IOException { 170 Bundle b; 171 try { 172 b = mExtras.getService().transceive(in); 173 } catch (RemoteException e) { 174 mExtras.attemptDeadServiceRecovery(e); 175 throw new IOException("NFC Service was dead, need to re-open"); 176 } 177 throwBundle(b); 178 return b.getByteArray("out"); 179 } 180 181 private static void throwBundle(Bundle b) throws IOException { 182 if (b.getInt("e") == -1) { 183 throw new IOException(b.getString("m")); 184 } 185 } 186} 187