15eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenpackage android.nfc.cardemulation; 25eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 35eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.annotation.SdkConstant; 45eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.annotation.SdkConstant.SdkConstantType; 55eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.app.Service; 65eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.content.Intent; 735bf6288527b177a04100585321a1266f020004aMartijn Coenenimport android.content.pm.PackageManager; 85eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.os.Bundle; 95eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.os.Handler; 105eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.os.IBinder; 115eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.os.Message; 125eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.os.Messenger; 135eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.os.RemoteException; 145eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.util.Log; 155eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 165eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen/** 1735bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>HostApduService is a convenience {@link Service} class that can be 1835bf6288527b177a04100585321a1266f020004aMartijn Coenen * extended to emulate an NFC card inside an Android 1935bf6288527b177a04100585321a1266f020004aMartijn Coenen * service component. 205eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * 2135bf6288527b177a04100585321a1266f020004aMartijn Coenen * <div class="special reference"> 2235bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>Developer Guide</h3> 2335bf6288527b177a04100585321a1266f020004aMartijn Coenen * For a general introduction into the topic of card emulation, 2435bf6288527b177a04100585321a1266f020004aMartijn Coenen * please read the <a href="{@docRoot}guide/topics/nfc/ce.html"> 2535bf6288527b177a04100585321a1266f020004aMartijn Coenen * NFC card emulation developer guide.</a></p> 2635bf6288527b177a04100585321a1266f020004aMartijn Coenen * </div> 2735bf6288527b177a04100585321a1266f020004aMartijn Coenen * 2835bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>NFC Protocols</h3> 2935bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>Cards emulated by this class are based on the NFC-Forum ISO-DEP 3035bf6288527b177a04100585321a1266f020004aMartijn Coenen * protocol (based on ISO/IEC 14443-4) and support processing 3135bf6288527b177a04100585321a1266f020004aMartijn Coenen * command Application Protocol Data Units (APDUs) as 3235bf6288527b177a04100585321a1266f020004aMartijn Coenen * defined in the ISO/IEC 7816-4 specification. 3335bf6288527b177a04100585321a1266f020004aMartijn Coenen * 3435bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>Service selection</h3> 3535bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>When a remote NFC device wants to talk to your 3635bf6288527b177a04100585321a1266f020004aMartijn Coenen * service, it sends a so-called 3735bf6288527b177a04100585321a1266f020004aMartijn Coenen * "SELECT AID" APDU as defined in the ISO/IEC 7816-4 specification. 3835bf6288527b177a04100585321a1266f020004aMartijn Coenen * The AID is an application identifier defined in ISO/IEC 7816-4. 3935bf6288527b177a04100585321a1266f020004aMartijn Coenen * 4035bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>The registration procedure for AIDs is defined in the 4135bf6288527b177a04100585321a1266f020004aMartijn Coenen * ISO/IEC 7816-5 specification. If you don't want to register an 4235bf6288527b177a04100585321a1266f020004aMartijn Coenen * AID, you are free to use AIDs in the proprietary range: 4335bf6288527b177a04100585321a1266f020004aMartijn Coenen * bits 8-5 of the first byte must each be set to '1'. For example, 4435bf6288527b177a04100585321a1266f020004aMartijn Coenen * "0xF00102030405" is a proprietary AID. If you do use proprietary 4535bf6288527b177a04100585321a1266f020004aMartijn Coenen * AIDs, it is recommended to choose an AID of at least 6 bytes, 4635bf6288527b177a04100585321a1266f020004aMartijn Coenen * to reduce the risk of collisions with other applications that 4735bf6288527b177a04100585321a1266f020004aMartijn Coenen * might be using proprietary AIDs as well. 4835bf6288527b177a04100585321a1266f020004aMartijn Coenen * 4935bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>AID groups</h3> 5035bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>In some cases, a service may need to register multiple AIDs 5135bf6288527b177a04100585321a1266f020004aMartijn Coenen * to implement a certain application, and it needs to be sure 5235bf6288527b177a04100585321a1266f020004aMartijn Coenen * that it is the default handler for all of these AIDs (as opposed 5335bf6288527b177a04100585321a1266f020004aMartijn Coenen * to some AIDs in the group going to another service). 5435bf6288527b177a04100585321a1266f020004aMartijn Coenen * 5535bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>An AID group is a list of AIDs that should be considered as 5635bf6288527b177a04100585321a1266f020004aMartijn Coenen * belonging together by the OS. For all AIDs in an AID group, the 5735bf6288527b177a04100585321a1266f020004aMartijn Coenen * OS will guarantee one of the following: 5835bf6288527b177a04100585321a1266f020004aMartijn Coenen * <ul> 5935bf6288527b177a04100585321a1266f020004aMartijn Coenen * <li>All AIDs in the group are routed to this service 6035bf6288527b177a04100585321a1266f020004aMartijn Coenen * <li>No AIDs in the group are routed to this service 6135bf6288527b177a04100585321a1266f020004aMartijn Coenen * </ul> 6235bf6288527b177a04100585321a1266f020004aMartijn Coenen * In other words, there is no in-between state, where some AIDs 6335bf6288527b177a04100585321a1266f020004aMartijn Coenen * in the group can be routed to this service, and some to another. 6435bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>AID groups and categories</h3> 6535bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>Each AID group can be associated with a category. This allows 6635bf6288527b177a04100585321a1266f020004aMartijn Coenen * the Android OS to classify services, and it allows the user to 6735bf6288527b177a04100585321a1266f020004aMartijn Coenen * set defaults at the category level instead of the AID level. 6835bf6288527b177a04100585321a1266f020004aMartijn Coenen * 6935bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>You can use 7035bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String)} 7135bf6288527b177a04100585321a1266f020004aMartijn Coenen * to determine if your service is the default handler for a category. 7235bf6288527b177a04100585321a1266f020004aMartijn Coenen * 7335bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>In this version of the platform, the only known categories 7435bf6288527b177a04100585321a1266f020004aMartijn Coenen * are {@link CardEmulation#CATEGORY_PAYMENT} and {@link CardEmulation#CATEGORY_OTHER}. 7535bf6288527b177a04100585321a1266f020004aMartijn Coenen * AID groups without a category, or with a category that is not recognized 7635bf6288527b177a04100585321a1266f020004aMartijn Coenen * by the current platform version, will automatically be 7735bf6288527b177a04100585321a1266f020004aMartijn Coenen * grouped into the {@link CardEmulation#CATEGORY_OTHER} category. 7835bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>Service AID registration</h3> 7935bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>To tell the platform which AIDs groups 8035bf6288527b177a04100585321a1266f020004aMartijn Coenen * are requested by this service, a {@link #SERVICE_META_DATA} 815eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * entry must be included in the declaration of the service. An 8235bf6288527b177a04100585321a1266f020004aMartijn Coenen * example of a HostApduService manifest declaration is shown below: 8335bf6288527b177a04100585321a1266f020004aMartijn Coenen * <pre> <service android:name=".MyHostApduService" android:exported="true" android:permission="android.permission.BIND_NFC_SERVICE"> 845eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * <intent-filter> 8535bf6288527b177a04100585321a1266f020004aMartijn Coenen * <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/> 865eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * </intent-filter> 8735bf6288527b177a04100585321a1266f020004aMartijn Coenen * <meta-data android:name="android.nfc.cardemulation.host_apdu_ervice" android:resource="@xml/apduservice"/> 885eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * </service></pre> 8935bf6288527b177a04100585321a1266f020004aMartijn Coenen * 9035bf6288527b177a04100585321a1266f020004aMartijn Coenen * This meta-data tag points to an apduservice.xml file. 9135bf6288527b177a04100585321a1266f020004aMartijn Coenen * An example of this file with a single AID group declaration is shown below: 9235bf6288527b177a04100585321a1266f020004aMartijn Coenen * <pre> 9335bf6288527b177a04100585321a1266f020004aMartijn Coenen * <host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android" 9435bf6288527b177a04100585321a1266f020004aMartijn Coenen * android:description="@string/servicedesc" android:requireDeviceUnlock="false"> 9535bf6288527b177a04100585321a1266f020004aMartijn Coenen * <aid-group android:description="@string/aiddescription" android:category="other"> 9635bf6288527b177a04100585321a1266f020004aMartijn Coenen * <aid-filter android:name="F0010203040506"/> 9735bf6288527b177a04100585321a1266f020004aMartijn Coenen * <aid-filter android:name="F0394148148100"/> 9835bf6288527b177a04100585321a1266f020004aMartijn Coenen * </aid-group> 9935bf6288527b177a04100585321a1266f020004aMartijn Coenen * </host-apdu-service> 10035bf6288527b177a04100585321a1266f020004aMartijn Coenen * </pre> 10135bf6288527b177a04100585321a1266f020004aMartijn Coenen * 10235bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>The {@link android.R.styleable#HostApduService <host-apdu-service>} is required 10335bf6288527b177a04100585321a1266f020004aMartijn Coenen * to contain a 10435bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link android.R.styleable#HostApduService_description <android:description>} 10535bf6288527b177a04100585321a1266f020004aMartijn Coenen * attribute that contains a user-friendly description of the service that may be shown in UI. 10635bf6288527b177a04100585321a1266f020004aMartijn Coenen * The 10735bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link android.R.styleable#HostApduService_requireDeviceUnlock <requireDeviceUnlock>} 10835bf6288527b177a04100585321a1266f020004aMartijn Coenen * attribute can be used to specify that the device must be unlocked before this service 10935bf6288527b177a04100585321a1266f020004aMartijn Coenen * can be invoked to handle APDUs. 11035bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>The {@link android.R.styleable#HostApduService <host-apdu-service>} must 11135bf6288527b177a04100585321a1266f020004aMartijn Coenen * contain one or more {@link android.R.styleable#AidGroup <aid-group>} tags. 11235bf6288527b177a04100585321a1266f020004aMartijn Coenen * Each {@link android.R.styleable#AidGroup <aid-group>} must contain one or 11335bf6288527b177a04100585321a1266f020004aMartijn Coenen * more {@link android.R.styleable#AidFilter <aid-filter>} tags, each of which 11435bf6288527b177a04100585321a1266f020004aMartijn Coenen * contains a single AID. The AID must be specified in hexadecimal format, and contain 11535bf6288527b177a04100585321a1266f020004aMartijn Coenen * an even number of characters. 11635bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>AID conflict resolution</h3> 11735bf6288527b177a04100585321a1266f020004aMartijn Coenen * Multiple HostApduServices may be installed on a single device, and the same AID 11835bf6288527b177a04100585321a1266f020004aMartijn Coenen * can be registered by more than one service. The Android platform resolves AID 11935bf6288527b177a04100585321a1266f020004aMartijn Coenen * conflicts depending on which category an AID belongs to. Each category may 12035bf6288527b177a04100585321a1266f020004aMartijn Coenen * have a different conflict resolution policy. For example, for some categories 12135bf6288527b177a04100585321a1266f020004aMartijn Coenen * the user may be able to select a default service in the Android settings UI. 12235bf6288527b177a04100585321a1266f020004aMartijn Coenen * For other categories, to policy may be to always ask the user which service 12335bf6288527b177a04100585321a1266f020004aMartijn Coenen * is to be invoked in case of conflict. 12435bf6288527b177a04100585321a1266f020004aMartijn Coenen * 12535bf6288527b177a04100585321a1266f020004aMartijn Coenen * To query the conflict resolution policy for a certain category, see 12635bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link CardEmulation#getSelectionModeForCategory(String)}. 12735bf6288527b177a04100585321a1266f020004aMartijn Coenen * 12835bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>Data exchange</h3> 12935bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>Once the platform has resolved a "SELECT AID" command APDU to a specific 13035bf6288527b177a04100585321a1266f020004aMartijn Coenen * service component, the "SELECT AID" command APDU and all subsequent 13135bf6288527b177a04100585321a1266f020004aMartijn Coenen * command APDUs will be sent to that service through 13235bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link #processCommandApdu(byte[], Bundle)}, until either: 13335bf6288527b177a04100585321a1266f020004aMartijn Coenen * <ul> 13435bf6288527b177a04100585321a1266f020004aMartijn Coenen * <li>The NFC link is broken</li> 13535bf6288527b177a04100585321a1266f020004aMartijn Coenen * <li>A "SELECT AID" APDU is received which resolves to another service</li> 13635bf6288527b177a04100585321a1266f020004aMartijn Coenen * </ul> 13735bf6288527b177a04100585321a1266f020004aMartijn Coenen * These two scenarios are indicated by a call to {@link #onDeactivated(int)}. 13835bf6288527b177a04100585321a1266f020004aMartijn Coenen * 13935bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p class="note">Use of this class requires the 14035bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} to be present 14135bf6288527b177a04100585321a1266f020004aMartijn Coenen * on the device. 14235bf6288527b177a04100585321a1266f020004aMartijn Coenen * 1435eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 1445eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenpublic abstract class HostApduService extends Service { 1455eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 14635bf6288527b177a04100585321a1266f020004aMartijn Coenen * The {@link Intent} action that must be declared as handled by the service. 1475eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 1485eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen @SdkConstant(SdkConstantType.SERVICE_ACTION) 1495eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public static final String SERVICE_INTERFACE = 15052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen "android.nfc.cardemulation.action.HOST_APDU_SERVICE"; 15152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 15252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 15352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * The name of the meta-data element that contains 15452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * more information about this service. 15552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 15652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final String SERVICE_META_DATA = 15752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen "android.nfc.cardemulation.host_apdu_service"; 15852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 15952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 1605eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * Reason for {@link #onDeactivated(int)}. 1615eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * Indicates deactivation was due to the NFC link 1625eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * being lost. 1635eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 1645eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public static final int DEACTIVATION_LINK_LOSS = 0; 1655eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 1665eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 1675eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * Reason for {@link #onDeactivated(int)}. 1685eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * 1695eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * <p>Indicates deactivation was due to a different AID 1705eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * being selected (which implicitly deselects the AID 1715eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * currently active on the logical channel). 1725eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * 1735eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * <p>Note that this next AID may still be resolved to this 174c85fb576b817aae2d853b6f5cb6effb924b892edMartijn Coenen * service, in which case {@link #processCommandApdu(byte[], Bundle)} 1755eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * will be called again. 1765eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 1775eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public static final int DEACTIVATION_DESELECTED = 1; 1785eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 1795eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen static final String TAG = "ApduService"; 1805eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 1815eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 1825eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * MSG_COMMAND_APDU is sent by NfcService when 1835eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * a 7816-4 command APDU has been received. 1845eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * 1855eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * @hide 1865eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 1875eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public static final int MSG_COMMAND_APDU = 0; 1885eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 1895eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 1905eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * MSG_RESPONSE_APDU is sent to NfcService to send 1915eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * a response APDU back to the remote device. 1925eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * 1935eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * @hide 1945eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 1955eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public static final int MSG_RESPONSE_APDU = 1; 1965eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 1975eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 1985eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * MSG_DEACTIVATED is sent by NfcService when 1995eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * the current session is finished; either because 2005eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * another AID was selected that resolved to 2015eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * another service, or because the NFC link 2025eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * was deactivated. 2035eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * 2045eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * @hide 2055eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 2065eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public static final int MSG_DEACTIVATED = 2; 2075eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 2085eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 209583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 210583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * @hide 211583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen */ 212583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen public static final int MSG_UNHANDLED = 3; 213583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen 214583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen /** 2155eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * @hide 2165eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 2175eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public static final String KEY_DATA = "data"; 2185eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 2195eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 2205eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * Messenger interface to NfcService for sending responses. 2215eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * Only accessed on main thread by the message handler. 222583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 223583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * @hide 2245eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 2255eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Messenger mNfcService = null; 2265eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 2275eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen final Messenger mMessenger = new Messenger(new MsgHandler()); 2285eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 2295eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen final class MsgHandler extends Handler { 2305eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen @Override 2315eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public void handleMessage(Message msg) { 2325eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen switch (msg.what) { 2335eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen case MSG_COMMAND_APDU: 2345eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Bundle dataBundle = msg.getData(); 2355eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen if (dataBundle == null) { 2365eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen return; 2375eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2385eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen if (mNfcService == null) mNfcService = msg.replyTo; 2395eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 2405eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen byte[] apdu = dataBundle.getByteArray(KEY_DATA); 2415eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen if (apdu != null) { 242fb2f8337f6fca9809156ddbaf0a7fe468bc1329fMartijn Coenen byte[] responseApdu = processCommandApdu(apdu, null); 2435eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen if (responseApdu != null) { 2445eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen if (mNfcService == null) { 2455eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Log.e(TAG, "Response not sent; service was deactivated."); 2465eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen return; 2475eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2485eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Message responseMsg = Message.obtain(null, MSG_RESPONSE_APDU); 2495eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Bundle responseBundle = new Bundle(); 2505eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen responseBundle.putByteArray(KEY_DATA, responseApdu); 2515eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen responseMsg.setData(responseBundle); 252583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen responseMsg.replyTo = mMessenger; 2535eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen try { 2545eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen mNfcService.send(responseMsg); 2555eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } catch (RemoteException e) { 2565eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Log.e("TAG", "Response not sent; RemoteException calling into " + 2575eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen "NfcService."); 2585eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2595eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2605eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } else { 2615eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Log.e(TAG, "Received MSG_COMMAND_APDU without data."); 2625eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2635eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen break; 2645eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen case MSG_RESPONSE_APDU: 2655eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen if (mNfcService == null) { 2665eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Log.e(TAG, "Response not sent; service was deactivated."); 2675eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen return; 2685eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2695eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen try { 270583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen msg.replyTo = mMessenger; 2715eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen mNfcService.send(msg); 2725eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } catch (RemoteException e) { 2735eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Log.e(TAG, "RemoteException calling into NfcService."); 2745eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2755eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen break; 2765eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen case MSG_DEACTIVATED: 2775eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen // Make sure we won't call into NfcService again 2785eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen mNfcService = null; 2795eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen onDeactivated(msg.arg1); 2805eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen break; 281583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen case MSG_UNHANDLED: 282583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen if (mNfcService == null) { 283583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen Log.e(TAG, "notifyUnhandled not sent; service was deactivated."); 284583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen return; 285583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen } 286583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen try { 287583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen msg.replyTo = mMessenger; 288583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen mNfcService.send(msg); 289583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen } catch (RemoteException e) { 290583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen Log.e(TAG, "RemoteException calling into NfcService."); 291583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen } 292583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen break; 2935eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen default: 2945eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen super.handleMessage(msg); 2955eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2965eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2975eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2985eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 2995eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen @Override 3005eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public final IBinder onBind(Intent intent) { 3015eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen return mMessenger.getBinder(); 3025eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 3035eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 3045eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 3055eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * Sends a response APDU back to the remote device. 3065eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * 3075eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * <p>Note: this method may be called from any thread and will not block. 3085eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * @param responseApdu A byte-array containing the reponse APDU. 3095eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 3105eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public final void sendResponseApdu(byte[] responseApdu) { 3115eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Message responseMsg = Message.obtain(null, MSG_RESPONSE_APDU); 3125eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Bundle dataBundle = new Bundle(); 3135eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen dataBundle.putByteArray(KEY_DATA, responseApdu); 3145eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen responseMsg.setData(dataBundle); 3155eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen try { 3165eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen mMessenger.send(responseMsg); 3175eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } catch (RemoteException e) { 3185eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Log.e("TAG", "Local messenger has died."); 3195eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 3205eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 3215eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 3225eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 323583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * Calling this method allows the service to tell the OS 324583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * that it won't be able to complete this transaction - 325583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * for example, because it requires data connectivity 326583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * that is not present at that moment. 327583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 328583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * The OS may use this indication to give the user a list 329583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * of alternative applications that can handle the last 330583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * AID that was selected. If the user would select an 331583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * application from the list, that action by itself 332583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * will not cause the default to be changed; the selected 333583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * application will be invoked for the next tap only. 334583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 335583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * If there are no other applications that can handle 336583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * this transaction, the OS will show an error dialog 337583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * indicating your service could not complete the 338583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * transaction. 339583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 340583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * <p>Note: this method may be called anywhere between 341c85fb576b817aae2d853b6f5cb6effb924b892edMartijn Coenen * the first {@link #processCommandApdu(byte[], Bundle)} 342583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * call and a {@link #onDeactivated(int)} call. 343583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen */ 344583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen public final void notifyUnhandled() { 345583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen Message unhandledMsg = Message.obtain(null, MSG_UNHANDLED); 346583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen try { 347583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen mMessenger.send(unhandledMsg); 348583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen } catch (RemoteException e) { 349583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen Log.e("TAG", "Local messenger has died."); 350583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen } 351583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen } 352583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen 353583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen 354583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen /** 355583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * <p>This method will be called when a command APDU has been received 356583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * from a remote device. A response APDU can be provided directly 357583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * by returning a byte-array in this method. Note that in general 358583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * response APDUs must be sent as quickly as possible, given the fact 359583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * that the user is likely holding his device over an NFC reader 360583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * when this method is called. 361583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 362583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * <p class="note">If there are multiple services that have registered for the same 363583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * AIDs in their meta-data entry, you will only get called if the user has 364583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * explicitly selected your service, either as a default or just for the next tap. 365583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 366583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * <p class="note">This method is running on the main thread of your application. 367583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * If you cannot return a response APDU immediately, return null 368583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * and use the {@link #sendResponseApdu(byte[])} method later. 369583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 37035bf6288527b177a04100585321a1266f020004aMartijn Coenen * @param commandApdu The APDU that was received from the remote device 371583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * @param extras A bundle containing extra data. May be null. 372583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * @return a byte-array containing the response APDU, or null if no 373583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * response APDU can be sent at this point. 374583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen */ 37551b6322197da054715e53d02754bc81caa8fd456Martijn Coenen public abstract byte[] processCommandApdu(byte[] commandApdu, Bundle extras); 3765eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 3775eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 3785eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * This method will be called in two possible scenarios: 3795eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * <li>The NFC link has been deactivated or lost 3805eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * <li>A different AID has been selected and was resolved to a different 3815eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * service component 3825eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * @param reason Either {@link #DEACTIVATION_LINK_LOSS} or {@link #DEACTIVATION_DESELECTED} 3835eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 3845eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public abstract void onDeactivated(int reason); 3855eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen} 386