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