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> &lt;service android:name=".MyHostApduService" android:exported="true" android:permission="android.permission.BIND_NFC_SERVICE"&gt;
845eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen *     &lt;intent-filter&gt;
8535bf6288527b177a04100585321a1266f020004aMartijn Coenen *         &lt;action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/&gt;
865eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen *     &lt;/intent-filter&gt;
8735bf6288527b177a04100585321a1266f020004aMartijn Coenen *     &lt;meta-data android:name="android.nfc.cardemulation.host_apdu_ervice" android:resource="@xml/apduservice"/&gt;
885eaa8970aa86fa32a6cbb47e0681000ed2d22c57Martijn Coenen * &lt;/service&gt;</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 * &lt;host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
9435bf6288527b177a04100585321a1266f020004aMartijn Coenen *           android:description="@string/servicedesc" android:requireDeviceUnlock="false"&gt;
9535bf6288527b177a04100585321a1266f020004aMartijn Coenen *       &lt;aid-group android:description="@string/aiddescription" android:category="other">
9635bf6288527b177a04100585321a1266f020004aMartijn Coenen *           &lt;aid-filter android:name="F0010203040506"/&gt;
9735bf6288527b177a04100585321a1266f020004aMartijn Coenen *           &lt;aid-filter android:name="F0394148148100"/&gt;
9835bf6288527b177a04100585321a1266f020004aMartijn Coenen *       &lt;/aid-group&gt;
9935bf6288527b177a04100585321a1266f020004aMartijn Coenen * &lt;/host-apdu-service&gt;
10035bf6288527b177a04100585321a1266f020004aMartijn Coenen * </pre>
10135bf6288527b177a04100585321a1266f020004aMartijn Coenen *
10235bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p>The {@link android.R.styleable#HostApduService &lt;host-apdu-service&gt;} is required
10335bf6288527b177a04100585321a1266f020004aMartijn Coenen * to contain a
10435bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link android.R.styleable#HostApduService_description &lt;android:description&gt;}
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 &lt;requireDeviceUnlock&gt;}
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 &lt;host-apdu-service&gt;} must
11135bf6288527b177a04100585321a1266f020004aMartijn Coenen * contain one or more {@link android.R.styleable#AidGroup &lt;aid-group&gt;} tags.
11235bf6288527b177a04100585321a1266f020004aMartijn Coenen * Each {@link android.R.styleable#AidGroup &lt;aid-group&gt;} must contain one or
11335bf6288527b177a04100585321a1266f020004aMartijn Coenen * more {@link android.R.styleable#AidFilter &lt;aid-filter&gt;} 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