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.content.Context; 20 import android.nfc.ErrorCodes; 21 import android.nfc.tech.Ndef; 22 import android.nfc.tech.TagTechnology; 23 import android.util.Log; 24 25 import com.android.nfc.DeviceHost; 26 import com.android.nfc.LlcpException; 27 import com.android.nfc.NfcDiscoveryParameters; 28 29 import java.util.Arrays; 30 import java.util.Iterator; 31 import java.util.HashMap; 32 33 /** 34 * Native interface to the NFC Manager functions 35 */ 36 public class NativeNfcManager implements DeviceHost { 37 private static final String TAG = "NativeNfcManager"; 38 static final String PREF = "NciDeviceHost"; 39 40 static final int DEFAULT_LLCP_MIU = 1980; 41 static final int DEFAULT_LLCP_RWSIZE = 2; 42 43 static final String DRIVER_NAME = "android-nci"; 44 45 static { 46 System.loadLibrary("nfc_nci_jni"); 47 } 48 49 /* Native structure */ 50 private long mNative; 51 52 private final DeviceHostListener mListener; 53 private final Context mContext; 54 55 private final Object mLock = new Object(); 56 private final HashMap<Integer, byte[]> mT3tIdentifiers = new HashMap<Integer, byte[]>(); 57 NativeNfcManager(Context context, DeviceHostListener listener)58 public NativeNfcManager(Context context, DeviceHostListener listener) { 59 mListener = listener; 60 initializeNativeStructure(); 61 mContext = context; 62 } 63 initializeNativeStructure()64 public native boolean initializeNativeStructure(); 65 doDownload()66 private native boolean doDownload(); 67 doGetLastError()68 public native int doGetLastError(); 69 70 @Override checkFirmware()71 public void checkFirmware() { 72 doDownload(); 73 } 74 doInitialize()75 private native boolean doInitialize(); 76 77 @Override initialize()78 public boolean initialize() { 79 return doInitialize(); 80 } 81 doDeinitialize()82 private native boolean doDeinitialize(); 83 84 @Override deinitialize()85 public boolean deinitialize() { 86 return doDeinitialize(); 87 } 88 89 @Override getName()90 public String getName() { 91 return DRIVER_NAME; 92 } 93 94 @Override sendRawFrame(byte[] data)95 public native boolean sendRawFrame(byte[] data); 96 97 @Override routeAid(byte[] aid, int route)98 public native boolean routeAid(byte[] aid, int route); 99 100 @Override unrouteAid(byte[] aid)101 public native boolean unrouteAid(byte[] aid); 102 103 @Override commitRouting()104 public native boolean commitRouting(); 105 doRegisterT3tIdentifier(byte[] t3tIdentifier)106 public native int doRegisterT3tIdentifier(byte[] t3tIdentifier); 107 108 @Override registerT3tIdentifier(byte[] t3tIdentifier)109 public void registerT3tIdentifier(byte[] t3tIdentifier) { 110 synchronized (mLock) { 111 int handle = doRegisterT3tIdentifier(t3tIdentifier); 112 if (handle != 0xffff) { 113 mT3tIdentifiers.put(Integer.valueOf(handle), t3tIdentifier); 114 } 115 } 116 } 117 doDeregisterT3tIdentifier(int handle)118 public native void doDeregisterT3tIdentifier(int handle); 119 120 @Override deregisterT3tIdentifier(byte[] t3tIdentifier)121 public void deregisterT3tIdentifier(byte[] t3tIdentifier) { 122 synchronized (mLock) { 123 Iterator<Integer> it = mT3tIdentifiers.keySet().iterator(); 124 while (it.hasNext()) { 125 int handle = it.next().intValue(); 126 byte[] value = mT3tIdentifiers.get(handle); 127 if (Arrays.equals(value, t3tIdentifier)) { 128 doDeregisterT3tIdentifier(handle); 129 mT3tIdentifiers.remove(handle); 130 break; 131 } 132 } 133 } 134 } 135 136 @Override clearT3tIdentifiersCache()137 public void clearT3tIdentifiersCache() { 138 synchronized (mLock) { 139 mT3tIdentifiers.clear(); 140 } 141 } 142 143 @Override getLfT3tMax()144 public native int getLfT3tMax(); 145 doEnableDiscovery(int techMask, boolean enableLowPowerPolling, boolean enableReaderMode, boolean enableHostRouting, boolean enableP2p, boolean restart)146 private native void doEnableDiscovery(int techMask, 147 boolean enableLowPowerPolling, 148 boolean enableReaderMode, 149 boolean enableHostRouting, 150 boolean enableP2p, 151 boolean restart); 152 @Override enableDiscovery(NfcDiscoveryParameters params, boolean restart)153 public void enableDiscovery(NfcDiscoveryParameters params, boolean restart) { 154 doEnableDiscovery(params.getTechMask(), params.shouldEnableLowPowerDiscovery(), 155 params.shouldEnableReaderMode(), params.shouldEnableHostRouting(), 156 params.shouldEnableP2p(), restart); 157 } 158 159 @Override disableDiscovery()160 public native void disableDiscovery(); 161 doCreateLlcpConnectionlessSocket(int nSap, String sn)162 private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, 163 String sn); 164 165 @Override createLlcpConnectionlessSocket(int nSap, String sn)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 doCreateLlcpServiceSocket(int nSap, String sn, int miu, int rw, int linearBufferLength)187 private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, 188 int rw, int linearBufferLength); 189 @Override createLlcpServerSocket(int nSap, String sn, int miu, int rw, int linearBufferLength)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 doCreateLlcpSocket(int sap, int miu, int rw, int linearBufferLength)211 private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, 212 int linearBufferLength); 213 @Override createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)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 doCheckLlcp()236 public native boolean doCheckLlcp(); 237 238 @Override doActivateLlcp()239 public native boolean doActivateLlcp(); 240 doResetTimeouts()241 private native void doResetTimeouts(); 242 243 @Override resetTimeouts()244 public void resetTimeouts() { 245 doResetTimeouts(); 246 } 247 248 @Override doAbort(String msg)249 public native void doAbort(String msg); 250 doSetTimeout(int tech, int timeout)251 private native boolean doSetTimeout(int tech, int timeout); 252 @Override setTimeout(int tech, int timeout)253 public boolean setTimeout(int tech, int timeout) { 254 return doSetTimeout(tech, timeout); 255 } 256 doGetTimeout(int tech)257 private native int doGetTimeout(int tech); 258 @Override getTimeout(int tech)259 public int getTimeout(int tech) { 260 return doGetTimeout(tech); 261 } 262 263 264 @Override canMakeReadOnly(int ndefType)265 public boolean canMakeReadOnly(int ndefType) { 266 return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2); 267 } 268 269 @Override getMaxTransceiveLength(int technology)270 public int getMaxTransceiveLength(int technology) { 271 switch (technology) { 272 case (TagTechnology.NFC_A): 273 case (TagTechnology.MIFARE_CLASSIC): 274 case (TagTechnology.MIFARE_ULTRALIGHT): 275 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC 276 case (TagTechnology.NFC_B): 277 ///////////////////////////////////////////////////////////////// 278 // Broadcom: Since BCM2079x supports this, set NfcB max size. 279 //return 0; // PN544 does not support transceive of raw NfcB 280 return 253; // PN544 does not support transceive of raw NfcB 281 case (TagTechnology.NFC_V): 282 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC 283 case (TagTechnology.ISO_DEP): 284 /* The maximum length of a normal IsoDep frame consists of: 285 * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes 286 * such a frame is supported. Extended length frames however 287 * are not supported. 288 */ 289 return 261; // Will be automatically split in two frames on the RF layer 290 case (TagTechnology.NFC_F): 291 return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC 292 default: 293 return 0; 294 } 295 296 } 297 doSetP2pInitiatorModes(int modes)298 private native void doSetP2pInitiatorModes(int modes); 299 @Override setP2pInitiatorModes(int modes)300 public void setP2pInitiatorModes(int modes) { 301 doSetP2pInitiatorModes(modes); 302 } 303 doSetP2pTargetModes(int modes)304 private native void doSetP2pTargetModes(int modes); 305 @Override setP2pTargetModes(int modes)306 public void setP2pTargetModes(int modes) { 307 doSetP2pTargetModes(modes); 308 } 309 310 @Override getExtendedLengthApdusSupported()311 public boolean getExtendedLengthApdusSupported() { 312 // TODO check BCM support 313 return false; 314 } 315 316 @Override getDefaultLlcpMiu()317 public int getDefaultLlcpMiu() { 318 return DEFAULT_LLCP_MIU; 319 } 320 321 @Override getDefaultLlcpRwSize()322 public int getDefaultLlcpRwSize() { 323 return DEFAULT_LLCP_RWSIZE; 324 } 325 doDump()326 private native String doDump(); 327 @Override dump()328 public String dump() { 329 return doDump(); 330 } 331 doEnableScreenOffSuspend()332 private native void doEnableScreenOffSuspend(); 333 @Override enableScreenOffSuspend()334 public boolean enableScreenOffSuspend() { 335 doEnableScreenOffSuspend(); 336 return true; 337 } 338 doDisableScreenOffSuspend()339 private native void doDisableScreenOffSuspend(); 340 @Override disableScreenOffSuspend()341 public boolean disableScreenOffSuspend() { 342 doDisableScreenOffSuspend(); 343 return true; 344 } 345 346 /** 347 * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) 348 */ notifyNdefMessageListeners(NativeNfcTag tag)349 private void notifyNdefMessageListeners(NativeNfcTag tag) { 350 mListener.onRemoteEndpointDiscovered(tag); 351 } 352 353 /** 354 * Notifies P2P Device detected, to activate LLCP link 355 */ notifyLlcpLinkActivation(NativeP2pDevice device)356 private void notifyLlcpLinkActivation(NativeP2pDevice device) { 357 mListener.onLlcpLinkActivated(device); 358 } 359 360 /** 361 * Notifies P2P Device detected, to activate LLCP link 362 */ notifyLlcpLinkDeactivated(NativeP2pDevice device)363 private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { 364 mListener.onLlcpLinkDeactivated(device); 365 } 366 367 /** 368 * Notifies first packet received from remote LLCP 369 */ notifyLlcpLinkFirstPacketReceived(NativeP2pDevice device)370 private void notifyLlcpLinkFirstPacketReceived(NativeP2pDevice device) { 371 mListener.onLlcpFirstPacketReceived(device); 372 } 373 notifyHostEmuActivated(int technology)374 private void notifyHostEmuActivated(int technology) { 375 mListener.onHostCardEmulationActivated(technology); 376 } 377 notifyHostEmuData(int technology, byte[] data)378 private void notifyHostEmuData(int technology, byte[] data) { 379 mListener.onHostCardEmulationData(technology, data); 380 } 381 notifyHostEmuDeactivated(int technology)382 private void notifyHostEmuDeactivated(int technology) { 383 mListener.onHostCardEmulationDeactivated(technology); 384 } 385 notifyRfFieldActivated()386 private void notifyRfFieldActivated() { 387 mListener.onRemoteFieldActivated(); 388 } 389 notifyRfFieldDeactivated()390 private void notifyRfFieldDeactivated() { 391 mListener.onRemoteFieldDeactivated(); 392 } 393 394 } 395