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 import com.android.nfc.NfcDiscoveryParameters;
     31 
     32 import java.io.File;
     33 
     34 /**
     35  * Native interface to the NFC Manager functions
     36  */
     37 public class NativeNfcManager implements DeviceHost {
     38     private static final String TAG = "NativeNfcManager";
     39 
     40     private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so";
     41 
     42     static final String PREF = "NxpDeviceHost";
     43 
     44     private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime";
     45     private static final long FIRMWARE_MODTIME_DEFAULT = -1;
     46 
     47     static final String DRIVER_NAME = "nxp";
     48 
     49     static final int DEFAULT_LLCP_MIU = 128;
     50     static final int DEFAULT_LLCP_RWSIZE = 1;
     51 
     52     static {
     53         System.loadLibrary("nfc_jni");
     54     }
     55 
     56     /* Native structure */
     57     private long mNative;
     58 
     59     private final DeviceHostListener mListener;
     60     private final Context mContext;
     61 
     62     public NativeNfcManager(Context context, DeviceHostListener listener) {
     63         mListener = listener;
     64         initializeNativeStructure();
     65         mContext = context;
     66     }
     67 
     68     public native boolean initializeNativeStructure();
     69 
     70     private native boolean doDownload();
     71 
     72     public native int doGetLastError();
     73 
     74     @Override
     75     public void checkFirmware() {
     76         // Check that the NFC controller firmware is up to date.  This
     77         // ensures that firmware updates are applied in a timely fashion,
     78         // and makes it much less likely that the user will have to wait
     79         // for a firmware download when they enable NFC in the settings
     80         // app.  Firmware download can take some time, so this should be
     81         // run in a separate thread.
     82 
     83         // check the timestamp of the firmware file
     84         File firmwareFile;
     85         int nbRetry = 0;
     86         try {
     87             firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME);
     88         } catch(NullPointerException npe) {
     89             Log.e(TAG,"path to firmware file was null");
     90             return;
     91         }
     92 
     93         long modtime = firmwareFile.lastModified();
     94 
     95         SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
     96         long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT);
     97         Log.d(TAG,"prev modtime: " + prev_fw_modtime);
     98         Log.d(TAG,"new modtime: " + modtime);
     99         if (prev_fw_modtime == modtime) {
    100             return;
    101         }
    102 
    103         // FW download.
    104         while(nbRetry < 5) {
    105             Log.d(TAG,"Perform Download");
    106             if(doDownload()) {
    107                 Log.d(TAG,"Download Success");
    108                 // Now that we've finished updating the firmware, save the new modtime.
    109                 prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply();
    110                 break;
    111             } else {
    112                 Log.d(TAG,"Download Failed");
    113                 nbRetry++;
    114             }
    115         }
    116     }
    117 
    118     private native boolean doInitialize();
    119 
    120     @Override
    121     public boolean initialize() {
    122         return doInitialize();
    123     }
    124 
    125     private native boolean doDeinitialize();
    126 
    127     @Override
    128     public boolean deinitialize() {
    129         return doDeinitialize();
    130     }
    131 
    132     @Override
    133     public String getName() {
    134         return DRIVER_NAME;
    135     }
    136 
    137     @Override
    138     public boolean sendRawFrame(byte[] data)
    139     {
    140         return false;
    141     }
    142 
    143     @Override
    144     public boolean routeAid(byte[] aid, int route)
    145     {
    146         return false;
    147     }
    148 
    149     @Override
    150     public boolean unrouteAid(byte[] aid)
    151     {
    152        return false;
    153     }
    154 
    155     @Override
    156     public boolean commitRouting()
    157     {
    158         return false;
    159     }
    160 
    161     private native void doEnableDiscovery(int techMask,
    162                                           boolean enableLowPowerPolling,
    163                                           boolean enableReaderMode,
    164                                           boolean enableP2p,
    165                                           boolean restart);
    166     @Override
    167     public void enableDiscovery(NfcDiscoveryParameters params, boolean restart) {
    168         doEnableDiscovery(params.getTechMask(), params.shouldEnableLowPowerDiscovery(),
    169                 params.shouldEnableReaderMode(), params.shouldEnableP2p(), restart);
    170     }
    171 
    172     @Override
    173     public native void disableDiscovery();
    174 
    175     private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap,
    176             String sn);
    177 
    178     @Override
    179     public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn)
    180             throws LlcpException {
    181         LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn);
    182         if (socket != null) {
    183             return socket;
    184         } else {
    185             /* Get Error Status */
    186             int error = doGetLastError();
    187 
    188             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
    189 
    190             switch (error) {
    191                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
    192                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
    193                     throw new LlcpException(error);
    194                 default:
    195                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
    196             }
    197         }
    198     }
    199 
    200     private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
    201             int rw, int linearBufferLength);
    202     @Override
    203     public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu,
    204             int rw, int linearBufferLength) throws LlcpException {
    205         LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength);
    206         if (socket != null) {
    207             return socket;
    208         } else {
    209             /* Get Error Status */
    210             int error = doGetLastError();
    211 
    212             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
    213 
    214             switch (error) {
    215                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
    216                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
    217                     throw new LlcpException(error);
    218                 default:
    219                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
    220             }
    221         }
    222     }
    223 
    224     private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
    225             int linearBufferLength);
    226     @Override
    227     public LlcpSocket createLlcpSocket(int sap, int miu, int rw,
    228             int linearBufferLength) throws LlcpException {
    229         LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
    230         if (socket != null) {
    231             return socket;
    232         } else {
    233             /* Get Error Status */
    234             int error = doGetLastError();
    235 
    236             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
    237 
    238             switch (error) {
    239                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
    240                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
    241                     throw new LlcpException(error);
    242                 default:
    243                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
    244             }
    245         }
    246     }
    247 
    248     @Override
    249     public native boolean doCheckLlcp();
    250 
    251     @Override
    252     public native boolean doActivateLlcp();
    253 
    254     private native void doResetTimeouts();
    255 
    256     @Override
    257     public void resetTimeouts() {
    258         doResetTimeouts();
    259     }
    260 
    261     @Override
    262     public native void doAbort();
    263 
    264     private native boolean doSetTimeout(int tech, int timeout);
    265     @Override
    266     public boolean setTimeout(int tech, int timeout) {
    267         return doSetTimeout(tech, timeout);
    268     }
    269 
    270     private native int doGetTimeout(int tech);
    271     @Override
    272     public int getTimeout(int tech) {
    273         return doGetTimeout(tech);
    274     }
    275 
    276 
    277     @Override
    278     public boolean canMakeReadOnly(int ndefType) {
    279         return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 ||
    280                 ndefType == Ndef.TYPE_MIFARE_CLASSIC);
    281     }
    282 
    283     @Override
    284     public int getMaxTransceiveLength(int technology) {
    285         switch (technology) {
    286             case (TagTechnology.NFC_A):
    287             case (TagTechnology.MIFARE_CLASSIC):
    288             case (TagTechnology.MIFARE_ULTRALIGHT):
    289                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
    290             case (TagTechnology.NFC_B):
    291                 return 0; // PN544 does not support transceive of raw NfcB
    292             case (TagTechnology.NFC_V):
    293                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
    294             case (TagTechnology.ISO_DEP):
    295                 /* The maximum length of a normal IsoDep frame consists of:
    296                  * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes
    297                  * such a frame is supported. Extended length frames however
    298                  * are not supported.
    299                  */
    300                 return 261; // Will be automatically split in two frames on the RF layer
    301             case (TagTechnology.NFC_F):
    302                 return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC
    303             default:
    304                 return 0;
    305         }
    306 
    307     }
    308 
    309     private native void doSetP2pInitiatorModes(int modes);
    310     @Override
    311     public void setP2pInitiatorModes(int modes) {
    312         doSetP2pInitiatorModes(modes);
    313     }
    314 
    315     private native void doSetP2pTargetModes(int modes);
    316     @Override
    317     public void setP2pTargetModes(int modes) {
    318         doSetP2pTargetModes(modes);
    319     }
    320 
    321     @Override
    322     public boolean enableScreenOffSuspend() {
    323         // Snooze mode not supported on NXP silicon
    324         Log.i(TAG, "Snooze mode is not supported on NXP NFCC");
    325         return false;
    326     }
    327 
    328     @Override
    329     public boolean disableScreenOffSuspend() {
    330         // Snooze mode not supported on NXP silicon
    331         Log.i(TAG, "Snooze mode is not supported on NXP NFCC");
    332         return true;
    333     }
    334 
    335     @Override
    336     public boolean getExtendedLengthApdusSupported() {
    337         // Not supported on the PN544
    338         return false;
    339     }
    340 
    341     @Override
    342     public int getDefaultLlcpMiu() {
    343         return DEFAULT_LLCP_MIU;
    344     }
    345 
    346     @Override
    347     public int getDefaultLlcpRwSize() {
    348         return DEFAULT_LLCP_RWSIZE;
    349     }
    350 
    351     private native String doDump();
    352     @Override
    353     public String dump() {
    354         return doDump();
    355     }
    356 
    357     /**
    358      * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
    359      */
    360     private void notifyNdefMessageListeners(NativeNfcTag tag) {
    361         mListener.onRemoteEndpointDiscovered(tag);
    362     }
    363 
    364     /**
    365      * Notifies P2P Device detected, to activate LLCP link
    366      */
    367     private void notifyLlcpLinkActivation(NativeP2pDevice device) {
    368         mListener.onLlcpLinkActivated(device);
    369     }
    370 
    371     /**
    372      * Notifies P2P Device detected, to activate LLCP link
    373      */
    374     private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
    375         mListener.onLlcpLinkDeactivated(device);
    376     }
    377 
    378     private void notifyRfFieldActivated() {
    379         mListener.onRemoteFieldActivated();
    380     }
    381 
    382     private void notifyRfFieldDeactivated() {
    383         mListener.onRemoteFieldDeactivated();
    384     }
    385 }
    386