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 58 public NativeNfcManager(Context context, DeviceHostListener listener) { 59 mListener = listener; 60 initializeNativeStructure(); 61 mContext = context; 62 } 63 64 public native boolean initializeNativeStructure(); 65 66 private native boolean doDownload(); 67 68 public native int doGetLastError(); 69 70 @Override 71 public void checkFirmware() { 72 doDownload(); 73 } 74 75 private native boolean doInitialize(); 76 77 @Override 78 public boolean initialize() { 79 return doInitialize(); 80 } 81 82 private native boolean doDeinitialize(); 83 84 @Override 85 public boolean deinitialize() { 86 return doDeinitialize(); 87 } 88 89 @Override 90 public String getName() { 91 return DRIVER_NAME; 92 } 93 94 @Override 95 public native boolean sendRawFrame(byte[] data); 96 97 @Override 98 public native boolean routeAid(byte[] aid, int route); 99 100 @Override 101 public native boolean unrouteAid(byte[] aid); 102 103 @Override 104 public native boolean commitRouting(); 105 106 public native int doRegisterT3tIdentifier(byte[] t3tIdentifier); 107 108 @Override 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 118 public native void doDeregisterT3tIdentifier(int handle); 119 120 @Override 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 137 public void clearT3tIdentifiersCache() { 138 synchronized (mLock) { 139 mT3tIdentifiers.clear(); 140 } 141 } 142 143 @Override 144 public native int getLfT3tMax(); 145 146 private native void doEnableDiscovery(int techMask, 147 boolean enableLowPowerPolling, 148 boolean enableReaderMode, 149 boolean enableHostRouting, 150 boolean enableP2p, 151 boolean restart); 152 @Override 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 160 public native void disableDiscovery(); 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 } 268 269 @Override 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 298 private native void doSetP2pInitiatorModes(int modes); 299 @Override 300 public void setP2pInitiatorModes(int modes) { 301 doSetP2pInitiatorModes(modes); 302 } 303 304 private native void doSetP2pTargetModes(int modes); 305 @Override 306 public void setP2pTargetModes(int modes) { 307 doSetP2pTargetModes(modes); 308 } 309 310 @Override 311 public boolean getExtendedLengthApdusSupported() { 312 // TODO check BCM support 313 return false; 314 } 315 316 @Override 317 public int getDefaultLlcpMiu() { 318 return DEFAULT_LLCP_MIU; 319 } 320 321 @Override 322 public int getDefaultLlcpRwSize() { 323 return DEFAULT_LLCP_RWSIZE; 324 } 325 326 private native String doDump(); 327 @Override 328 public String dump() { 329 return doDump(); 330 } 331 332 private native void doEnableScreenOffSuspend(); 333 @Override 334 public boolean enableScreenOffSuspend() { 335 doEnableScreenOffSuspend(); 336 return true; 337 } 338 339 private native void doDisableScreenOffSuspend(); 340 @Override 341 public boolean disableScreenOffSuspend() { 342 doDisableScreenOffSuspend(); 343 return true; 344 } 345 346 /** 347 * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) 348 */ 349 private void notifyNdefMessageListeners(NativeNfcTag tag) { 350 mListener.onRemoteEndpointDiscovered(tag); 351 } 352 353 /** 354 * Notifies P2P Device detected, to activate LLCP link 355 */ 356 private void notifyLlcpLinkActivation(NativeP2pDevice device) { 357 mListener.onLlcpLinkActivated(device); 358 } 359 360 /** 361 * Notifies P2P Device detected, to activate LLCP link 362 */ 363 private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { 364 mListener.onLlcpLinkDeactivated(device); 365 } 366 367 /** 368 * Notifies first packet received from remote LLCP 369 */ 370 private void notifyLlcpLinkFirstPacketReceived(NativeP2pDevice device) { 371 mListener.onLlcpFirstPacketReceived(device); 372 } 373 374 private void notifyHostEmuActivated(int technology) { 375 mListener.onHostCardEmulationActivated(technology); 376 } 377 378 private void notifyHostEmuData(int technology, byte[] data) { 379 mListener.onHostCardEmulationData(technology, data); 380 } 381 382 private void notifyHostEmuDeactivated(int technology) { 383 mListener.onHostCardEmulationDeactivated(technology); 384 } 385 386 private void notifyRfFieldActivated() { 387 mListener.onRemoteFieldActivated(); 388 } 389 390 private void notifyRfFieldDeactivated() { 391 mListener.onRemoteFieldDeactivated(); 392 } 393 394 } 395