Home | History | Annotate | Download | only in dhimpl
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.nfc.dhimpl;
     18 
     19 import android.annotation.SdkConstant;
     20 import android.annotation.SdkConstant.SdkConstantType;
     21 import android.content.Context;
     22 import android.content.SharedPreferences;
     23 import android.nfc.ErrorCodes;
     24 import android.nfc.tech.Ndef;
     25 import android.nfc.tech.TagTechnology;
     26 import android.util.Log;
     27 
     28 import com.android.nfc.DeviceHost;
     29 import com.android.nfc.LlcpException;
     30 
     31 /**
     32  * Native interface to the NFC Manager functions
     33  */
     34 public class NativeNfcManager implements DeviceHost {
     35     private static final String TAG = "NativeNfcManager";
     36     static final String PREF = "NciDeviceHost";
     37 
     38     static final int DEFAULT_LLCP_MIU = 1980;
     39     static final int DEFAULT_LLCP_RWSIZE = 2;
     40 
     41     static final String DRIVER_NAME = "android-nci";
     42 
     43     private static final byte[][] EE_WIPE_APDUS = {
     44         {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
     45         {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
     46                 (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00},
     47         {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00},
     48         {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
     49         {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
     50                 (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00},
     51         {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00},
     52         {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
     53     };
     54 
     55     static {
     56         System.loadLibrary("nfc_nci_jni");
     57     }
     58 
     59     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     60     public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED";
     61 
     62     /* Native structure */
     63     private int mNative;
     64 
     65     private final DeviceHostListener mListener;
     66     private final Context mContext;
     67 
     68     public NativeNfcManager(Context context, DeviceHostListener listener) {
     69         mListener = listener;
     70         initializeNativeStructure();
     71         mContext = context;
     72     }
     73 
     74     public native boolean initializeNativeStructure();
     75 
     76     private native boolean doDownload();
     77 
     78     public native int doGetLastError();
     79 
     80     @Override
     81     public void checkFirmware() {
     82         doDownload();
     83     }
     84 
     85     private native boolean doInitialize();
     86 
     87     @Override
     88     public boolean initialize() {
     89         SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
     90         SharedPreferences.Editor editor = prefs.edit();
     91 
     92         if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) {
     93             try {
     94                 Thread.sleep (12000);
     95                 editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
     96                 editor.apply();
     97             } catch (InterruptedException e) { }
     98         }
     99 
    100         return doInitialize();
    101     }
    102 
    103     private native boolean doDeinitialize();
    104 
    105     @Override
    106     public boolean deinitialize() {
    107         SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
    108         SharedPreferences.Editor editor = prefs.edit();
    109 
    110         editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
    111         editor.apply();
    112 
    113         return doDeinitialize();
    114     }
    115 
    116     @Override
    117     public String getName() {
    118         return DRIVER_NAME;
    119     }
    120 
    121     @Override
    122     public native boolean sendRawFrame(byte[] data);
    123 
    124     @Override
    125     public native boolean routeAid(byte[] aid, int route);
    126 
    127     @Override
    128     public native boolean unrouteAid(byte[] aid);
    129 
    130     @Override
    131     public native void enableDiscovery();
    132 
    133     @Override
    134     public native void disableDiscovery();
    135 
    136     @Override
    137     public native void enableRoutingToHost();
    138 
    139     @Override
    140     public native void disableRoutingToHost();
    141 
    142     @Override
    143     public native int[] doGetSecureElementList();
    144 
    145     @Override
    146     public native void doSelectSecureElement();
    147 
    148     @Override
    149     public native void doDeselectSecureElement();
    150 
    151 
    152     private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap,
    153             String sn);
    154 
    155     @Override
    156     public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn)
    157             throws LlcpException {
    158         LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn);
    159         if (socket != null) {
    160             return socket;
    161         } else {
    162             /* Get Error Status */
    163             int error = doGetLastError();
    164 
    165             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
    166 
    167             switch (error) {
    168                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
    169                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
    170                     throw new LlcpException(error);
    171                 default:
    172                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
    173             }
    174         }
    175     }
    176 
    177     private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
    178             int rw, int linearBufferLength);
    179     @Override
    180     public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu,
    181             int rw, int linearBufferLength) throws LlcpException {
    182         LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength);
    183         if (socket != null) {
    184             return socket;
    185         } else {
    186             /* Get Error Status */
    187             int error = doGetLastError();
    188 
    189             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
    190 
    191             switch (error) {
    192                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
    193                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
    194                     throw new LlcpException(error);
    195                 default:
    196                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
    197             }
    198         }
    199     }
    200 
    201     private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
    202             int linearBufferLength);
    203     @Override
    204     public LlcpSocket createLlcpSocket(int sap, int miu, int rw,
    205             int linearBufferLength) throws LlcpException {
    206         LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
    207         if (socket != null) {
    208             return socket;
    209         } else {
    210             /* Get Error Status */
    211             int error = doGetLastError();
    212 
    213             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
    214 
    215             switch (error) {
    216                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
    217                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
    218                     throw new LlcpException(error);
    219                 default:
    220                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
    221             }
    222         }
    223     }
    224 
    225     @Override
    226     public native boolean doCheckLlcp();
    227 
    228     @Override
    229     public native boolean doActivateLlcp();
    230 
    231     private native void doResetTimeouts();
    232 
    233     @Override
    234     public void resetTimeouts() {
    235         doResetTimeouts();
    236     }
    237 
    238     @Override
    239     public native void doAbort();
    240 
    241     private native boolean doSetTimeout(int tech, int timeout);
    242     @Override
    243     public boolean setTimeout(int tech, int timeout) {
    244         return doSetTimeout(tech, timeout);
    245     }
    246 
    247     private native int doGetTimeout(int tech);
    248     @Override
    249     public int getTimeout(int tech) {
    250         return doGetTimeout(tech);
    251     }
    252 
    253 
    254     @Override
    255     public boolean canMakeReadOnly(int ndefType) {
    256         return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2);
    257     }
    258 
    259     @Override
    260     public int getMaxTransceiveLength(int technology) {
    261         switch (technology) {
    262             case (TagTechnology.NFC_A):
    263             case (TagTechnology.MIFARE_CLASSIC):
    264             case (TagTechnology.MIFARE_ULTRALIGHT):
    265                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
    266             case (TagTechnology.NFC_B):
    267                 /////////////////////////////////////////////////////////////////
    268                 // Broadcom: Since BCM2079x supports this, set NfcB max size.
    269                 //return 0; // PN544 does not support transceive of raw NfcB
    270                 return 253; // PN544 does not support transceive of raw NfcB
    271             case (TagTechnology.NFC_V):
    272                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
    273             case (TagTechnology.ISO_DEP):
    274                 /* The maximum length of a normal IsoDep frame consists of:
    275                  * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes
    276                  * such a frame is supported. Extended length frames however
    277                  * are not supported.
    278                  */
    279                 return 261; // Will be automatically split in two frames on the RF layer
    280             case (TagTechnology.NFC_F):
    281                 return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC
    282             default:
    283                 return 0;
    284         }
    285 
    286     }
    287 
    288     private native void doSetP2pInitiatorModes(int modes);
    289     @Override
    290     public void setP2pInitiatorModes(int modes) {
    291         doSetP2pInitiatorModes(modes);
    292     }
    293 
    294     private native void doSetP2pTargetModes(int modes);
    295     @Override
    296     public void setP2pTargetModes(int modes) {
    297         doSetP2pTargetModes(modes);
    298     }
    299 
    300     @Override
    301     public boolean getExtendedLengthApdusSupported() {
    302         // TODO check BCM support
    303         return false;
    304     }
    305 
    306     @Override
    307     public boolean enablePN544Quirks() {
    308         return false;
    309     }
    310 
    311     @Override
    312     public byte[][] getWipeApdus() {
    313         return EE_WIPE_APDUS;
    314     }
    315 
    316     @Override
    317     public int getDefaultLlcpMiu() {
    318         return DEFAULT_LLCP_MIU;
    319     }
    320 
    321     @Override
    322     public int getDefaultLlcpRwSize() {
    323         return DEFAULT_LLCP_RWSIZE;
    324     }
    325 
    326     private native String doDump();
    327     @Override
    328     public String dump() {
    329         return doDump();
    330     }
    331 
    332     private native void doEnableReaderMode(int technologies);
    333     @Override
    334     public boolean enableReaderMode(int technologies) {
    335         doEnableReaderMode(technologies);
    336         return true;
    337     }
    338 
    339     private native void doDisableReaderMode();
    340     @Override
    341     public boolean disableReaderMode() {
    342         doDisableReaderMode();
    343         return true;
    344     }
    345 
    346     /**
    347      * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
    348      */
    349     private void notifyNdefMessageListeners(NativeNfcTag tag) {
    350         mListener.onRemoteEndpointDiscovered(tag);
    351     }
    352 
    353     /**
    354      * Notifies transaction
    355      */
    356     private void notifyTargetDeselected() {
    357         mListener.onCardEmulationDeselected();
    358     }
    359 
    360     /**
    361      * Notifies transaction
    362      */
    363     private void notifyTransactionListeners(byte[] aid) {
    364         mListener.onCardEmulationAidSelected(aid);
    365     }
    366 
    367     /**
    368      * Notifies P2P Device detected, to activate LLCP link
    369      */
    370     private void notifyLlcpLinkActivation(NativeP2pDevice device) {
    371         mListener.onLlcpLinkActivated(device);
    372     }
    373 
    374     /**
    375      * Notifies P2P Device detected, to activate LLCP link
    376      */
    377     private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
    378         mListener.onLlcpLinkDeactivated(device);
    379     }
    380 
    381     /**
    382      * Notifies first packet received from remote LLCP
    383      */
    384     private void notifyLlcpLinkFirstPacketReceived(NativeP2pDevice device) {
    385         mListener.onLlcpFirstPacketReceived(device);
    386     }
    387 
    388     private void notifySeFieldActivated() {
    389         mListener.onRemoteFieldActivated();
    390     }
    391 
    392     private void notifySeFieldDeactivated() {
    393         mListener.onRemoteFieldDeactivated();
    394     }
    395 
    396     private void notifySeListenActivated() {
    397         mListener.onSeListenActivated();
    398     }
    399 
    400     private void notifySeListenDeactivated() {
    401         mListener.onSeListenDeactivated();
    402     }
    403 
    404     private void notifySeApduReceived(byte[] apdu) {
    405         mListener.onSeApduReceived(apdu);
    406     }
    407 
    408     private void notifySeEmvCardRemoval() {
    409         mListener.onSeEmvCardRemoval();
    410     }
    411 
    412     private void notifySeMifareAccess(byte[] block) {
    413         mListener.onSeMifareAccess(block);
    414     }
    415 
    416     private void notifyHostEmuActivated() {
    417         mListener.onHostCardEmulationActivated();
    418     }
    419 
    420     private void notifyHostEmuData(byte[] data) {
    421         mListener.onHostCardEmulationData(data);
    422     }
    423 
    424     private void notifyHostEmuDeactivated() {
    425         mListener.onHostCardEmulationDeactivated();
    426     }
    427 
    428 }
    429