1a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen/* 2a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen * Copyright (C) 2015 The Android Open Source Project 3a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen * 4a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen * Licensed under the Apache License, Version 2.0 (the "License"); 5a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen * you may not use this file except in compliance with the License. 6a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen * You may obtain a copy of the License at 7a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen * 8a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen * http://www.apache.org/licenses/LICENSE-2.0 9a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen * 10a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen * Unless required by applicable law or agreed to in writing, software 11a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen * distributed under the License is distributed on an "AS IS" BASIS, 12a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen * See the License for the specific language governing permissions and 14a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen * limitations under the License. 15a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen */ 16a1ec95882901ebf386cc794122b36b18ee845554Martijn Coenen 175eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenpackage android.nfc.cardemulation; 185eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 195eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.annotation.SdkConstant; 205eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.annotation.SdkConstant.SdkConstantType; 215eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.app.Service; 225eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.content.Intent; 2335bf6288527b177a04100585321a1266f020004aMartijn Coenenimport android.content.pm.PackageManager; 245eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.os.Bundle; 255eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.os.Handler; 265eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.os.IBinder; 275eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.os.Message; 285eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.os.Messenger; 295eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.os.RemoteException; 305eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenimport android.util.Log; 315eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 325eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen/** 3335bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>HostApduService is a convenience {@link Service} class that can be 3435bf6288527b177a04100585321a1266f020004aMartijn Coenen * extended to emulate an NFC card inside an Android 3535bf6288527b177a04100585321a1266f020004aMartijn Coenen * service component. 365eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * 3735bf6288527b177a04100585321a1266f020004aMartijn Coenen * <div class="special reference"> 3835bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>Developer Guide</h3> 39682c24e22811d4ee17ae1cd61bf255c3f7e722b7Trevor Johns * For a general introduction to card emulation, see 40682c24e22811d4ee17ae1cd61bf255c3f7e722b7Trevor Johns * <a href="{@docRoot}guide/topics/connectivity/nfc/hce.html"> 41682c24e22811d4ee17ae1cd61bf255c3f7e722b7Trevor Johns * Host-based Card Emulation</a>.</p> 4235bf6288527b177a04100585321a1266f020004aMartijn Coenen * </div> 4335bf6288527b177a04100585321a1266f020004aMartijn Coenen * 4435bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>NFC Protocols</h3> 4535bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>Cards emulated by this class are based on the NFC-Forum ISO-DEP 4635bf6288527b177a04100585321a1266f020004aMartijn Coenen * protocol (based on ISO/IEC 14443-4) and support processing 4735bf6288527b177a04100585321a1266f020004aMartijn Coenen * command Application Protocol Data Units (APDUs) as 4835bf6288527b177a04100585321a1266f020004aMartijn Coenen * defined in the ISO/IEC 7816-4 specification. 4935bf6288527b177a04100585321a1266f020004aMartijn Coenen * 5035bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>Service selection</h3> 5135bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>When a remote NFC device wants to talk to your 5235bf6288527b177a04100585321a1266f020004aMartijn Coenen * service, it sends a so-called 5335bf6288527b177a04100585321a1266f020004aMartijn Coenen * "SELECT AID" APDU as defined in the ISO/IEC 7816-4 specification. 5435bf6288527b177a04100585321a1266f020004aMartijn Coenen * The AID is an application identifier defined in ISO/IEC 7816-4. 5535bf6288527b177a04100585321a1266f020004aMartijn Coenen * 5635bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>The registration procedure for AIDs is defined in the 5735bf6288527b177a04100585321a1266f020004aMartijn Coenen * ISO/IEC 7816-5 specification. If you don't want to register an 5835bf6288527b177a04100585321a1266f020004aMartijn Coenen * AID, you are free to use AIDs in the proprietary range: 5935bf6288527b177a04100585321a1266f020004aMartijn Coenen * bits 8-5 of the first byte must each be set to '1'. For example, 6035bf6288527b177a04100585321a1266f020004aMartijn Coenen * "0xF00102030405" is a proprietary AID. If you do use proprietary 6135bf6288527b177a04100585321a1266f020004aMartijn Coenen * AIDs, it is recommended to choose an AID of at least 6 bytes, 6235bf6288527b177a04100585321a1266f020004aMartijn Coenen * to reduce the risk of collisions with other applications that 6335bf6288527b177a04100585321a1266f020004aMartijn Coenen * might be using proprietary AIDs as well. 6435bf6288527b177a04100585321a1266f020004aMartijn Coenen * 6535bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>AID groups</h3> 6635bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>In some cases, a service may need to register multiple AIDs 6735bf6288527b177a04100585321a1266f020004aMartijn Coenen * to implement a certain application, and it needs to be sure 6835bf6288527b177a04100585321a1266f020004aMartijn Coenen * that it is the default handler for all of these AIDs (as opposed 6935bf6288527b177a04100585321a1266f020004aMartijn Coenen * to some AIDs in the group going to another service). 7035bf6288527b177a04100585321a1266f020004aMartijn Coenen * 7135bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>An AID group is a list of AIDs that should be considered as 7235bf6288527b177a04100585321a1266f020004aMartijn Coenen * belonging together by the OS. For all AIDs in an AID group, the 7335bf6288527b177a04100585321a1266f020004aMartijn Coenen * OS will guarantee one of the following: 7435bf6288527b177a04100585321a1266f020004aMartijn Coenen * <ul> 7535bf6288527b177a04100585321a1266f020004aMartijn Coenen * <li>All AIDs in the group are routed to this service 7635bf6288527b177a04100585321a1266f020004aMartijn Coenen * <li>No AIDs in the group are routed to this service 7735bf6288527b177a04100585321a1266f020004aMartijn Coenen * </ul> 7835bf6288527b177a04100585321a1266f020004aMartijn Coenen * In other words, there is no in-between state, where some AIDs 7935bf6288527b177a04100585321a1266f020004aMartijn Coenen * in the group can be routed to this service, and some to another. 8035bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>AID groups and categories</h3> 8135bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>Each AID group can be associated with a category. This allows 8235bf6288527b177a04100585321a1266f020004aMartijn Coenen * the Android OS to classify services, and it allows the user to 8335bf6288527b177a04100585321a1266f020004aMartijn Coenen * set defaults at the category level instead of the AID level. 8435bf6288527b177a04100585321a1266f020004aMartijn Coenen * 8535bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>You can use 8635bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String)} 8735bf6288527b177a04100585321a1266f020004aMartijn Coenen * to determine if your service is the default handler for a category. 8835bf6288527b177a04100585321a1266f020004aMartijn Coenen * 8935bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>In this version of the platform, the only known categories 9035bf6288527b177a04100585321a1266f020004aMartijn Coenen * are {@link CardEmulation#CATEGORY_PAYMENT} and {@link CardEmulation#CATEGORY_OTHER}. 9135bf6288527b177a04100585321a1266f020004aMartijn Coenen * AID groups without a category, or with a category that is not recognized 9235bf6288527b177a04100585321a1266f020004aMartijn Coenen * by the current platform version, will automatically be 9335bf6288527b177a04100585321a1266f020004aMartijn Coenen * grouped into the {@link CardEmulation#CATEGORY_OTHER} category. 9435bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>Service AID registration</h3> 9535bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>To tell the platform which AIDs groups 9635bf6288527b177a04100585321a1266f020004aMartijn Coenen * are requested by this service, a {@link #SERVICE_META_DATA} 975eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * entry must be included in the declaration of the service. An 9835bf6288527b177a04100585321a1266f020004aMartijn Coenen * example of a HostApduService manifest declaration is shown below: 9935bf6288527b177a04100585321a1266f020004aMartijn Coenen * <pre> <service android:name=".MyHostApduService" android:exported="true" android:permission="android.permission.BIND_NFC_SERVICE"> 1005eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * <intent-filter> 10135bf6288527b177a04100585321a1266f020004aMartijn Coenen * <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/> 1025eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * </intent-filter> 10335bf6288527b177a04100585321a1266f020004aMartijn Coenen * <meta-data android:name="android.nfc.cardemulation.host_apdu_ervice" android:resource="@xml/apduservice"/> 1045eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * </service></pre> 10535bf6288527b177a04100585321a1266f020004aMartijn Coenen * 10635bf6288527b177a04100585321a1266f020004aMartijn Coenen * This meta-data tag points to an apduservice.xml file. 10735bf6288527b177a04100585321a1266f020004aMartijn Coenen * An example of this file with a single AID group declaration is shown below: 10835bf6288527b177a04100585321a1266f020004aMartijn Coenen * <pre> 10935bf6288527b177a04100585321a1266f020004aMartijn Coenen * <host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android" 11035bf6288527b177a04100585321a1266f020004aMartijn Coenen * android:description="@string/servicedesc" android:requireDeviceUnlock="false"> 11135bf6288527b177a04100585321a1266f020004aMartijn Coenen * <aid-group android:description="@string/aiddescription" android:category="other"> 11235bf6288527b177a04100585321a1266f020004aMartijn Coenen * <aid-filter android:name="F0010203040506"/> 11335bf6288527b177a04100585321a1266f020004aMartijn Coenen * <aid-filter android:name="F0394148148100"/> 11435bf6288527b177a04100585321a1266f020004aMartijn Coenen * </aid-group> 11535bf6288527b177a04100585321a1266f020004aMartijn Coenen * </host-apdu-service> 11635bf6288527b177a04100585321a1266f020004aMartijn Coenen * </pre> 11735bf6288527b177a04100585321a1266f020004aMartijn Coenen * 11835bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>The {@link android.R.styleable#HostApduService <host-apdu-service>} is required 11935bf6288527b177a04100585321a1266f020004aMartijn Coenen * to contain a 12035bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link android.R.styleable#HostApduService_description <android:description>} 12135bf6288527b177a04100585321a1266f020004aMartijn Coenen * attribute that contains a user-friendly description of the service that may be shown in UI. 12235bf6288527b177a04100585321a1266f020004aMartijn Coenen * The 12335bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link android.R.styleable#HostApduService_requireDeviceUnlock <requireDeviceUnlock>} 12435bf6288527b177a04100585321a1266f020004aMartijn Coenen * attribute can be used to specify that the device must be unlocked before this service 12535bf6288527b177a04100585321a1266f020004aMartijn Coenen * can be invoked to handle APDUs. 12635bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>The {@link android.R.styleable#HostApduService <host-apdu-service>} must 12735bf6288527b177a04100585321a1266f020004aMartijn Coenen * contain one or more {@link android.R.styleable#AidGroup <aid-group>} tags. 12835bf6288527b177a04100585321a1266f020004aMartijn Coenen * Each {@link android.R.styleable#AidGroup <aid-group>} must contain one or 12935bf6288527b177a04100585321a1266f020004aMartijn Coenen * more {@link android.R.styleable#AidFilter <aid-filter>} tags, each of which 13035bf6288527b177a04100585321a1266f020004aMartijn Coenen * contains a single AID. The AID must be specified in hexadecimal format, and contain 13135bf6288527b177a04100585321a1266f020004aMartijn Coenen * an even number of characters. 13235bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>AID conflict resolution</h3> 13335bf6288527b177a04100585321a1266f020004aMartijn Coenen * Multiple HostApduServices may be installed on a single device, and the same AID 13435bf6288527b177a04100585321a1266f020004aMartijn Coenen * can be registered by more than one service. The Android platform resolves AID 13535bf6288527b177a04100585321a1266f020004aMartijn Coenen * conflicts depending on which category an AID belongs to. Each category may 13635bf6288527b177a04100585321a1266f020004aMartijn Coenen * have a different conflict resolution policy. For example, for some categories 13735bf6288527b177a04100585321a1266f020004aMartijn Coenen * the user may be able to select a default service in the Android settings UI. 13835bf6288527b177a04100585321a1266f020004aMartijn Coenen * For other categories, to policy may be to always ask the user which service 13935bf6288527b177a04100585321a1266f020004aMartijn Coenen * is to be invoked in case of conflict. 14035bf6288527b177a04100585321a1266f020004aMartijn Coenen * 14135bf6288527b177a04100585321a1266f020004aMartijn Coenen * To query the conflict resolution policy for a certain category, see 14235bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link CardEmulation#getSelectionModeForCategory(String)}. 14335bf6288527b177a04100585321a1266f020004aMartijn Coenen * 14435bf6288527b177a04100585321a1266f020004aMartijn Coenen * <h3>Data exchange</h3> 14535bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>Once the platform has resolved a "SELECT AID" command APDU to a specific 14635bf6288527b177a04100585321a1266f020004aMartijn Coenen * service component, the "SELECT AID" command APDU and all subsequent 14735bf6288527b177a04100585321a1266f020004aMartijn Coenen * command APDUs will be sent to that service through 14835bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link #processCommandApdu(byte[], Bundle)}, until either: 14935bf6288527b177a04100585321a1266f020004aMartijn Coenen * <ul> 15035bf6288527b177a04100585321a1266f020004aMartijn Coenen * <li>The NFC link is broken</li> 15135bf6288527b177a04100585321a1266f020004aMartijn Coenen * <li>A "SELECT AID" APDU is received which resolves to another service</li> 15235bf6288527b177a04100585321a1266f020004aMartijn Coenen * </ul> 15335bf6288527b177a04100585321a1266f020004aMartijn Coenen * These two scenarios are indicated by a call to {@link #onDeactivated(int)}. 15435bf6288527b177a04100585321a1266f020004aMartijn Coenen * 15535bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p class="note">Use of this class requires the 15635bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} to be present 15735bf6288527b177a04100585321a1266f020004aMartijn Coenen * on the device. 15835bf6288527b177a04100585321a1266f020004aMartijn Coenen * 1595eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 1605eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenenpublic abstract class HostApduService extends Service { 1615eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 16235bf6288527b177a04100585321a1266f020004aMartijn Coenen * The {@link Intent} action that must be declared as handled by the service. 1635eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 1645eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen @SdkConstant(SdkConstantType.SERVICE_ACTION) 1655eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public static final String SERVICE_INTERFACE = 16652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen "android.nfc.cardemulation.action.HOST_APDU_SERVICE"; 16752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 16852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 16952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * The name of the meta-data element that contains 17052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * more information about this service. 17152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */ 17252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen public static final String SERVICE_META_DATA = 17352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen "android.nfc.cardemulation.host_apdu_service"; 17452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen 17552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen /** 1765eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * Reason for {@link #onDeactivated(int)}. 1775eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * Indicates deactivation was due to the NFC link 1785eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * being lost. 1795eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 1805eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public static final int DEACTIVATION_LINK_LOSS = 0; 1815eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 1825eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 1835eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * Reason for {@link #onDeactivated(int)}. 1845eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * 1855eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * <p>Indicates deactivation was due to a different AID 1865eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * being selected (which implicitly deselects the AID 1875eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * currently active on the logical channel). 1885eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * 1895eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * <p>Note that this next AID may still be resolved to this 190c85fb576b817aae2d853b6f5cb6effb924b892edMartijn Coenen * service, in which case {@link #processCommandApdu(byte[], Bundle)} 1915eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * will be called again. 1925eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 1935eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public static final int DEACTIVATION_DESELECTED = 1; 1945eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 1955eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen static final String TAG = "ApduService"; 1965eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 1975eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 1985eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * MSG_COMMAND_APDU is sent by NfcService when 1995eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * a 7816-4 command APDU has been received. 2005eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * 2015eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * @hide 2025eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 2035eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public static final int MSG_COMMAND_APDU = 0; 2045eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 2055eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 2065eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * MSG_RESPONSE_APDU is sent to NfcService to send 2075eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * a response APDU back to the remote device. 2085eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * 2095eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * @hide 2105eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 2115eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public static final int MSG_RESPONSE_APDU = 1; 2125eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 2135eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 2145eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * MSG_DEACTIVATED is sent by NfcService when 2155eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * the current session is finished; either because 2165eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * another AID was selected that resolved to 2175eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * another service, or because the NFC link 2185eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * was deactivated. 2195eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * 2205eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * @hide 2215eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 2225eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public static final int MSG_DEACTIVATED = 2; 2235eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 2245eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 225583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 226583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * @hide 227583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen */ 228583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen public static final int MSG_UNHANDLED = 3; 229583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen 230583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen /** 2315eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * @hide 2325eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 2335eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public static final String KEY_DATA = "data"; 2345eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 2355eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 2365eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * Messenger interface to NfcService for sending responses. 2375eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * Only accessed on main thread by the message handler. 238583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 239583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * @hide 2405eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 2415eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Messenger mNfcService = null; 2425eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 2435eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen final Messenger mMessenger = new Messenger(new MsgHandler()); 2445eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 2455eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen final class MsgHandler extends Handler { 2465eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen @Override 2475eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public void handleMessage(Message msg) { 2485eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen switch (msg.what) { 2495eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen case MSG_COMMAND_APDU: 2505eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Bundle dataBundle = msg.getData(); 2515eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen if (dataBundle == null) { 2525eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen return; 2535eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2545eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen if (mNfcService == null) mNfcService = msg.replyTo; 2555eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 2565eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen byte[] apdu = dataBundle.getByteArray(KEY_DATA); 2575eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen if (apdu != null) { 258fb2f8337f6fca9809156ddbaf0a7fe468bc1329fMartijn Coenen byte[] responseApdu = processCommandApdu(apdu, null); 2595eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen if (responseApdu != null) { 2605eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen if (mNfcService == null) { 2615eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Log.e(TAG, "Response not sent; service was deactivated."); 2625eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen return; 2635eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2645eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Message responseMsg = Message.obtain(null, MSG_RESPONSE_APDU); 2655eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Bundle responseBundle = new Bundle(); 2665eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen responseBundle.putByteArray(KEY_DATA, responseApdu); 2675eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen responseMsg.setData(responseBundle); 268583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen responseMsg.replyTo = mMessenger; 2695eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen try { 2705eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen mNfcService.send(responseMsg); 2715eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } catch (RemoteException e) { 2725eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Log.e("TAG", "Response not sent; RemoteException calling into " + 2735eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen "NfcService."); 2745eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2755eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2765eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } else { 2775eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Log.e(TAG, "Received MSG_COMMAND_APDU without data."); 2785eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2795eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen break; 2805eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen case MSG_RESPONSE_APDU: 2815eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen if (mNfcService == null) { 2825eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Log.e(TAG, "Response not sent; service was deactivated."); 2835eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen return; 2845eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2855eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen try { 286583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen msg.replyTo = mMessenger; 2875eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen mNfcService.send(msg); 2885eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } catch (RemoteException e) { 2895eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Log.e(TAG, "RemoteException calling into NfcService."); 2905eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 2915eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen break; 2925eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen case MSG_DEACTIVATED: 2935eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen // Make sure we won't call into NfcService again 2945eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen mNfcService = null; 2955eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen onDeactivated(msg.arg1); 2965eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen break; 297583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen case MSG_UNHANDLED: 298583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen if (mNfcService == null) { 299583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen Log.e(TAG, "notifyUnhandled not sent; service was deactivated."); 300583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen return; 301583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen } 302583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen try { 303583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen msg.replyTo = mMessenger; 304583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen mNfcService.send(msg); 305583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen } catch (RemoteException e) { 306583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen Log.e(TAG, "RemoteException calling into NfcService."); 307583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen } 308583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen break; 3095eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen default: 3105eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen super.handleMessage(msg); 3115eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 3125eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 3135eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 3145eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 3155eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen @Override 3165eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public final IBinder onBind(Intent intent) { 3175eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen return mMessenger.getBinder(); 3185eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 3195eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 3205eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 3215eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * Sends a response APDU back to the remote device. 3225eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * 3235eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * <p>Note: this method may be called from any thread and will not block. 3245eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * @param responseApdu A byte-array containing the reponse APDU. 3255eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 3265eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public final void sendResponseApdu(byte[] responseApdu) { 3275eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Message responseMsg = Message.obtain(null, MSG_RESPONSE_APDU); 3285eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Bundle dataBundle = new Bundle(); 3295eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen dataBundle.putByteArray(KEY_DATA, responseApdu); 3305eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen responseMsg.setData(dataBundle); 3315eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen try { 3325eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen mMessenger.send(responseMsg); 3335eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } catch (RemoteException e) { 3345eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen Log.e("TAG", "Local messenger has died."); 3355eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 3365eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen } 3375eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 3385eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 339583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * Calling this method allows the service to tell the OS 340583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * that it won't be able to complete this transaction - 341583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * for example, because it requires data connectivity 342583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * that is not present at that moment. 343583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 344583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * The OS may use this indication to give the user a list 345583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * of alternative applications that can handle the last 346583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * AID that was selected. If the user would select an 347583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * application from the list, that action by itself 348583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * will not cause the default to be changed; the selected 349583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * application will be invoked for the next tap only. 350583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 351583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * If there are no other applications that can handle 352583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * this transaction, the OS will show an error dialog 353583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * indicating your service could not complete the 354583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * transaction. 355583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 356583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * <p>Note: this method may be called anywhere between 357c85fb576b817aae2d853b6f5cb6effb924b892edMartijn Coenen * the first {@link #processCommandApdu(byte[], Bundle)} 358583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * call and a {@link #onDeactivated(int)} call. 359583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen */ 360583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen public final void notifyUnhandled() { 361583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen Message unhandledMsg = Message.obtain(null, MSG_UNHANDLED); 362583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen try { 363583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen mMessenger.send(unhandledMsg); 364583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen } catch (RemoteException e) { 365583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen Log.e("TAG", "Local messenger has died."); 366583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen } 367583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen } 368583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen 369583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen 370583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen /** 371583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * <p>This method will be called when a command APDU has been received 372583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * from a remote device. A response APDU can be provided directly 373583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * by returning a byte-array in this method. Note that in general 374583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * response APDUs must be sent as quickly as possible, given the fact 375583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * that the user is likely holding his device over an NFC reader 376583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * when this method is called. 377583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 378583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * <p class="note">If there are multiple services that have registered for the same 379583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * AIDs in their meta-data entry, you will only get called if the user has 380583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * explicitly selected your service, either as a default or just for the next tap. 381583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 382583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * <p class="note">This method is running on the main thread of your application. 383583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * If you cannot return a response APDU immediately, return null 384583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * and use the {@link #sendResponseApdu(byte[])} method later. 385583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * 38635bf6288527b177a04100585321a1266f020004aMartijn Coenen * @param commandApdu The APDU that was received from the remote device 387583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * @param extras A bundle containing extra data. May be null. 388583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * @return a byte-array containing the response APDU, or null if no 389583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen * response APDU can be sent at this point. 390583fe9d22b21aa77fad3096bfdad3020d6088230Martijn Coenen */ 39151b6322197da054715e53d02754bc81caa8fd456Martijn Coenen public abstract byte[] processCommandApdu(byte[] commandApdu, Bundle extras); 3925eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen 3935eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen /** 3945eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * This method will be called in two possible scenarios: 3955eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * <li>The NFC link has been deactivated or lost 3965eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * <li>A different AID has been selected and was resolved to a different 3975eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * service component 3985eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * @param reason Either {@link #DEACTIVATION_LINK_LOSS} or {@link #DEACTIVATION_DESELECTED} 3995eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen */ 4005eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen public abstract void onDeactivated(int reason); 4015eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen} 402