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