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; 30import com.android.nfc.NfcDiscoveryParameters; 31 32import java.io.File; 33 34/** 35 * Native interface to the NFC Manager functions 36 */ 37public 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 restart); 165 @Override 166 public void enableDiscovery(NfcDiscoveryParameters params, boolean restart) { 167 doEnableDiscovery(params.getTechMask(), params.shouldEnableLowPowerDiscovery(), 168 params.shouldEnableReaderMode(), restart); 169 } 170 171 @Override 172 public native void disableDiscovery(); 173 174 private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, 175 String sn); 176 177 @Override 178 public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) 179 throws LlcpException { 180 LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); 181 if (socket != null) { 182 return socket; 183 } else { 184 /* Get Error Status */ 185 int error = doGetLastError(); 186 187 Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); 188 189 switch (error) { 190 case ErrorCodes.ERROR_BUFFER_TO_SMALL: 191 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: 192 throw new LlcpException(error); 193 default: 194 throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); 195 } 196 } 197 } 198 199 private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, 200 int rw, int linearBufferLength); 201 @Override 202 public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, 203 int rw, int linearBufferLength) throws LlcpException { 204 LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); 205 if (socket != null) { 206 return socket; 207 } else { 208 /* Get Error Status */ 209 int error = doGetLastError(); 210 211 Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); 212 213 switch (error) { 214 case ErrorCodes.ERROR_BUFFER_TO_SMALL: 215 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: 216 throw new LlcpException(error); 217 default: 218 throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); 219 } 220 } 221 } 222 223 private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, 224 int linearBufferLength); 225 @Override 226 public LlcpSocket createLlcpSocket(int sap, int miu, int rw, 227 int linearBufferLength) throws LlcpException { 228 LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); 229 if (socket != null) { 230 return socket; 231 } else { 232 /* Get Error Status */ 233 int error = doGetLastError(); 234 235 Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); 236 237 switch (error) { 238 case ErrorCodes.ERROR_BUFFER_TO_SMALL: 239 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: 240 throw new LlcpException(error); 241 default: 242 throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); 243 } 244 } 245 } 246 247 @Override 248 public native boolean doCheckLlcp(); 249 250 @Override 251 public native boolean doActivateLlcp(); 252 253 private native void doResetTimeouts(); 254 255 @Override 256 public void resetTimeouts() { 257 doResetTimeouts(); 258 } 259 260 @Override 261 public native void doAbort(); 262 263 private native boolean doSetTimeout(int tech, int timeout); 264 @Override 265 public boolean setTimeout(int tech, int timeout) { 266 return doSetTimeout(tech, timeout); 267 } 268 269 private native int doGetTimeout(int tech); 270 @Override 271 public int getTimeout(int tech) { 272 return doGetTimeout(tech); 273 } 274 275 276 @Override 277 public boolean canMakeReadOnly(int ndefType) { 278 return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || 279 ndefType == Ndef.TYPE_MIFARE_CLASSIC); 280 } 281 282 @Override 283 public int getMaxTransceiveLength(int technology) { 284 switch (technology) { 285 case (TagTechnology.NFC_A): 286 case (TagTechnology.MIFARE_CLASSIC): 287 case (TagTechnology.MIFARE_ULTRALIGHT): 288 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC 289 case (TagTechnology.NFC_B): 290 return 0; // PN544 does not support transceive of raw NfcB 291 case (TagTechnology.NFC_V): 292 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC 293 case (TagTechnology.ISO_DEP): 294 /* The maximum length of a normal IsoDep frame consists of: 295 * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes 296 * such a frame is supported. Extended length frames however 297 * are not supported. 298 */ 299 return 261; // Will be automatically split in two frames on the RF layer 300 case (TagTechnology.NFC_F): 301 return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC 302 default: 303 return 0; 304 } 305 306 } 307 308 private native void doSetP2pInitiatorModes(int modes); 309 @Override 310 public void setP2pInitiatorModes(int modes) { 311 doSetP2pInitiatorModes(modes); 312 } 313 314 private native void doSetP2pTargetModes(int modes); 315 @Override 316 public void setP2pTargetModes(int modes) { 317 doSetP2pTargetModes(modes); 318 } 319 320 @Override 321 public boolean enableScreenOffSuspend() { 322 // Snooze mode not supported on NXP silicon 323 Log.i(TAG, "Snooze mode is not supported on NXP NFCC"); 324 return false; 325 } 326 327 @Override 328 public boolean disableScreenOffSuspend() { 329 // Snooze mode not supported on NXP silicon 330 Log.i(TAG, "Snooze mode is not supported on NXP NFCC"); 331 return true; 332 } 333 334 @Override 335 public boolean getExtendedLengthApdusSupported() { 336 // Not supported on the PN544 337 return false; 338 } 339 340 @Override 341 public int getDefaultLlcpMiu() { 342 return DEFAULT_LLCP_MIU; 343 } 344 345 @Override 346 public int getDefaultLlcpRwSize() { 347 return DEFAULT_LLCP_RWSIZE; 348 } 349 350 private native String doDump(); 351 @Override 352 public String dump() { 353 return doDump(); 354 } 355 356 /** 357 * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) 358 */ 359 private void notifyNdefMessageListeners(NativeNfcTag tag) { 360 mListener.onRemoteEndpointDiscovered(tag); 361 } 362 363 /** 364 * Notifies P2P Device detected, to activate LLCP link 365 */ 366 private void notifyLlcpLinkActivation(NativeP2pDevice device) { 367 mListener.onLlcpLinkActivated(device); 368 } 369 370 /** 371 * Notifies P2P Device detected, to activate LLCP link 372 */ 373 private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { 374 mListener.onLlcpLinkDeactivated(device); 375 } 376 377 private void notifyRfFieldActivated() { 378 mListener.onRemoteFieldActivated(); 379 } 380 381 private void notifyRfFieldDeactivated() { 382 mListener.onRemoteFieldDeactivated(); 383 } 384} 385