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 com.android.nfc.DeviceHost;
     20 import com.android.nfc.LlcpException;
     21 
     22 import android.annotation.SdkConstant;
     23 import android.annotation.SdkConstant.SdkConstantType;
     24 import android.content.Context;
     25 import android.content.SharedPreferences;
     26 import android.nfc.ErrorCodes;
     27 import android.nfc.tech.Ndef;
     28 import android.nfc.tech.TagTechnology;
     29 import android.util.Log;
     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     }
     83 
     84     private native boolean doInitialize();
     85 
     86     @Override
     87     public boolean initialize() {
     88         SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
     89         SharedPreferences.Editor editor = prefs.edit();
     90 
     91         if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) {
     92             try {
     93                 Thread.sleep (12000);
     94                 editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
     95                 editor.apply();
     96             } catch (InterruptedException e) { }
     97         }
     98 
     99         return doInitialize();
    100     }
    101 
    102     private native boolean doDeinitialize();
    103 
    104     @Override
    105     public boolean deinitialize() {
    106         SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
    107         SharedPreferences.Editor editor = prefs.edit();
    108 
    109         editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
    110         editor.apply();
    111 
    112         return doDeinitialize();
    113     }
    114 
    115     @Override
    116     public String getName() {
    117         return DRIVER_NAME;
    118     }
    119 
    120     @Override
    121     public native void enableDiscovery();
    122 
    123     @Override
    124     public native void disableDiscovery();
    125 
    126     @Override
    127     public native int[] doGetSecureElementList();
    128 
    129     @Override
    130     public native void doSelectSecureElement();
    131 
    132     @Override
    133     public native void doDeselectSecureElement();
    134 
    135 
    136     private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap,
    137             String sn);
    138 
    139     @Override
    140     public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn)
    141             throws LlcpException {
    142         LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn);
    143         if (socket != null) {
    144             return socket;
    145         } else {
    146             /* Get Error Status */
    147             int error = doGetLastError();
    148 
    149             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
    150 
    151             switch (error) {
    152                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
    153                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
    154                     throw new LlcpException(error);
    155                 default:
    156                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
    157             }
    158         }
    159     }
    160 
    161     private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
    162             int rw, int linearBufferLength);
    163     @Override
    164     public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu,
    165             int rw, int linearBufferLength) throws LlcpException {
    166         LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength);
    167         if (socket != null) {
    168             return socket;
    169         } else {
    170             /* Get Error Status */
    171             int error = doGetLastError();
    172 
    173             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
    174 
    175             switch (error) {
    176                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
    177                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
    178                     throw new LlcpException(error);
    179                 default:
    180                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
    181             }
    182         }
    183     }
    184 
    185     private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
    186             int linearBufferLength);
    187     @Override
    188     public LlcpSocket createLlcpSocket(int sap, int miu, int rw,
    189             int linearBufferLength) throws LlcpException {
    190         LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
    191         if (socket != null) {
    192             return socket;
    193         } else {
    194             /* Get Error Status */
    195             int error = doGetLastError();
    196 
    197             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
    198 
    199             switch (error) {
    200                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
    201                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
    202                     throw new LlcpException(error);
    203                 default:
    204                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
    205             }
    206         }
    207     }
    208 
    209     @Override
    210     public native boolean doCheckLlcp();
    211 
    212     @Override
    213     public native boolean doActivateLlcp();
    214 
    215     private native void doResetTimeouts();
    216 
    217     @Override
    218     public void resetTimeouts() {
    219         doResetTimeouts();
    220     }
    221 
    222     @Override
    223     public native void doAbort();
    224 
    225     private native boolean doSetTimeout(int tech, int timeout);
    226     @Override
    227     public boolean setTimeout(int tech, int timeout) {
    228         return doSetTimeout(tech, timeout);
    229     }
    230 
    231     private native int doGetTimeout(int tech);
    232     @Override
    233     public int getTimeout(int tech) {
    234         return doGetTimeout(tech);
    235     }
    236 
    237 
    238     @Override
    239     public boolean canMakeReadOnly(int ndefType) {
    240         return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2);
    241     }
    242 
    243     @Override
    244     public int getMaxTransceiveLength(int technology) {
    245         switch (technology) {
    246             case (TagTechnology.NFC_A):
    247             case (TagTechnology.MIFARE_CLASSIC):
    248             case (TagTechnology.MIFARE_ULTRALIGHT):
    249                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
    250             case (TagTechnology.NFC_B):
    251                 /////////////////////////////////////////////////////////////////
    252                 // Broadcom: Since BCM2079x supports this, set NfcB max size.
    253                 //return 0; // PN544 does not support transceive of raw NfcB
    254                 return 253; // PN544 does not support transceive of raw NfcB
    255             case (TagTechnology.NFC_V):
    256                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
    257             case (TagTechnology.ISO_DEP):
    258                 /* The maximum length of a normal IsoDep frame consists of:
    259                  * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes
    260                  * such a frame is supported. Extended length frames however
    261                  * are not supported.
    262                  */
    263                 return 261; // Will be automatically split in two frames on the RF layer
    264             case (TagTechnology.NFC_F):
    265                 return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC
    266             default:
    267                 return 0;
    268         }
    269 
    270     }
    271 
    272     private native void doSetP2pInitiatorModes(int modes);
    273     @Override
    274     public void setP2pInitiatorModes(int modes) {
    275         doSetP2pInitiatorModes(modes);
    276     }
    277 
    278     private native void doSetP2pTargetModes(int modes);
    279     @Override
    280     public void setP2pTargetModes(int modes) {
    281         doSetP2pTargetModes(modes);
    282     }
    283     @Override
    284     public boolean getExtendedLengthApdusSupported() {
    285         // TODO check BCM support
    286         return false;
    287     }
    288 
    289     @Override
    290     public boolean enablePN544Quirks() {
    291         return false;
    292     }
    293 
    294     @Override
    295     public byte[][] getWipeApdus() {
    296         return EE_WIPE_APDUS;
    297     }
    298 
    299     @Override
    300     public int getDefaultLlcpMiu() {
    301         return DEFAULT_LLCP_MIU;
    302     }
    303 
    304     @Override
    305     public int getDefaultLlcpRwSize() {
    306         return DEFAULT_LLCP_RWSIZE;
    307     }
    308 
    309     private native String doDump();
    310     @Override
    311     public String dump() {
    312         return doDump();
    313     }
    314 
    315     /**
    316      * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
    317      */
    318     private void notifyNdefMessageListeners(NativeNfcTag tag) {
    319         mListener.onRemoteEndpointDiscovered(tag);
    320     }
    321 
    322     /**
    323      * Notifies transaction
    324      */
    325     private void notifyTargetDeselected() {
    326         mListener.onCardEmulationDeselected();
    327     }
    328 
    329     /**
    330      * Notifies transaction
    331      */
    332     private void notifyTransactionListeners(byte[] aid) {
    333         mListener.onCardEmulationAidSelected(aid);
    334     }
    335 
    336     /**
    337      * Notifies P2P Device detected, to activate LLCP link
    338      */
    339     private void notifyLlcpLinkActivation(NativeP2pDevice device) {
    340         mListener.onLlcpLinkActivated(device);
    341     }
    342 
    343     /**
    344      * Notifies P2P Device detected, to activate LLCP link
    345      */
    346     private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
    347         mListener.onLlcpLinkDeactivated(device);
    348     }
    349 
    350     /**
    351      * Notifies first packet received from remote LLCP
    352      */
    353     private void notifyLlcpLinkFirstPacketReceived(NativeP2pDevice device) {
    354         mListener.onLlcpFirstPacketReceived(device);
    355     }
    356 
    357     private void notifySeFieldActivated() {
    358         mListener.onRemoteFieldActivated();
    359     }
    360 
    361     private void notifySeFieldDeactivated() {
    362         mListener.onRemoteFieldDeactivated();
    363     }
    364 
    365     private void notifySeListenActivated() {
    366         mListener.onSeListenActivated();
    367     }
    368 
    369     private void notifySeListenDeactivated() {
    370         mListener.onSeListenDeactivated();
    371     }
    372 
    373     private void notifySeApduReceived(byte[] apdu) {
    374         mListener.onSeApduReceived(apdu);
    375     }
    376 
    377     private void notifySeEmvCardRemoval() {
    378         mListener.onSeEmvCardRemoval();
    379     }
    380 
    381     private void notifySeMifareAccess(byte[] block) {
    382         mListener.onSeMifareAccess(block);
    383     }
    384 
    385 }
    386