NativeNfcManager.java revision d2604c0544f7bc26e5b2407f0215cccfffedae2c
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 android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
21import android.content.Context;
22import android.content.SharedPreferences;
23import android.nfc.ErrorCodes;
24import android.nfc.tech.Ndef;
25import android.nfc.tech.TagTechnology;
26import android.util.Log;
27
28import com.android.nfc.DeviceHost;
29import com.android.nfc.LlcpException;
30
31/**
32 * Native interface to the NFC Manager functions
33 */
34public class NativeNfcManager implements DeviceHost {
35    private static final String TAG = "NativeNfcManager";
36    static final String PREF = "NciDeviceHost";
37
38    static final int DEFAULT_LLCP_MIU = 1980;
39    static final int DEFAULT_LLCP_RWSIZE = 2;
40
41    static final String DRIVER_NAME = "android-nci";
42
43    private static final byte[][] EE_WIPE_APDUS = {
44        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
45        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
46                (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00},
47        {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00},
48        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
49        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
50                (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00},
51        {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00},
52        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
53    };
54
55    static {
56        System.loadLibrary("nfc_nci_jni");
57    }
58
59
60    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
61    public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED";
62
63    /* Native structure */
64    private int mNative;
65
66    private final DeviceHostListener mListener;
67    private final Context mContext;
68
69
70    public NativeNfcManager(Context context, DeviceHostListener listener) {
71        mListener = listener;
72        initializeNativeStructure();
73        mContext = context;
74    }
75
76    public native boolean initializeNativeStructure();
77
78    private native boolean doDownload();
79
80    public native int doGetLastError();
81
82    @Override
83    public void checkFirmware() {
84        doDownload();
85    }
86
87    private native boolean doInitialize(boolean enableScreenOffSuspend);
88
89    @Override
90    public boolean initialize(boolean enableScreenOffSuspend) {
91        SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
92        SharedPreferences.Editor editor = prefs.edit();
93
94        if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) {
95            try {
96                Thread.sleep (12000);
97                editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
98                editor.apply();
99            } catch (InterruptedException e) { }
100        }
101
102        return doInitialize(enableScreenOffSuspend);
103    }
104
105    private native boolean doDeinitialize();
106
107    @Override
108    public boolean deinitialize() {
109        SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
110        SharedPreferences.Editor editor = prefs.edit();
111
112        editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
113        editor.apply();
114
115        return doDeinitialize();
116    }
117
118    @Override
119    public String getName() {
120        return DRIVER_NAME;
121    }
122
123    @Override
124    public native boolean sendRawFrame(byte[] data);
125
126    @Override
127    public native boolean routeAid(byte[] aid, int route);
128
129    @Override
130    public native boolean unrouteAid(byte[] aid);
131
132    @Override
133    public native void enableDiscovery(int techMask, boolean enableLowPowerDiscovery);
134
135    @Override
136    public native void disableDiscovery();
137
138    @Override
139    public native void enableRoutingToHost();
140
141    @Override
142    public native void disableRoutingToHost();
143
144    @Override
145    public native int[] doGetSecureElementList();
146
147    @Override
148    public native void doSelectSecureElement();
149
150    @Override
151    public native void doDeselectSecureElement();
152
153
154    private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap,
155            String sn);
156
157    @Override
158    public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn)
159            throws LlcpException {
160        LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn);
161        if (socket != null) {
162            return socket;
163        } else {
164            /* Get Error Status */
165            int error = doGetLastError();
166
167            Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
168
169            switch (error) {
170                case ErrorCodes.ERROR_BUFFER_TO_SMALL:
171                case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
172                    throw new LlcpException(error);
173                default:
174                    throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
175            }
176        }
177    }
178
179    private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
180            int rw, int linearBufferLength);
181    @Override
182    public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu,
183            int rw, int linearBufferLength) throws LlcpException {
184        LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength);
185        if (socket != null) {
186            return socket;
187        } else {
188            /* Get Error Status */
189            int error = doGetLastError();
190
191            Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
192
193            switch (error) {
194                case ErrorCodes.ERROR_BUFFER_TO_SMALL:
195                case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
196                    throw new LlcpException(error);
197                default:
198                    throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
199            }
200        }
201    }
202
203    private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
204            int linearBufferLength);
205    @Override
206    public LlcpSocket createLlcpSocket(int sap, int miu, int rw,
207            int linearBufferLength) throws LlcpException {
208        LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
209        if (socket != null) {
210            return socket;
211        } else {
212            /* Get Error Status */
213            int error = doGetLastError();
214
215            Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
216
217            switch (error) {
218                case ErrorCodes.ERROR_BUFFER_TO_SMALL:
219                case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
220                    throw new LlcpException(error);
221                default:
222                    throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
223            }
224        }
225    }
226
227    @Override
228    public native boolean doCheckLlcp();
229
230    @Override
231    public native boolean doActivateLlcp();
232
233    private native void doResetTimeouts();
234
235    @Override
236    public void resetTimeouts() {
237        doResetTimeouts();
238    }
239
240    @Override
241    public native void doAbort();
242
243    private native boolean doSetTimeout(int tech, int timeout);
244    @Override
245    public boolean setTimeout(int tech, int timeout) {
246        return doSetTimeout(tech, timeout);
247    }
248
249    private native int doGetTimeout(int tech);
250    @Override
251    public int getTimeout(int tech) {
252        return doGetTimeout(tech);
253    }
254
255
256    @Override
257    public boolean canMakeReadOnly(int ndefType) {
258        return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2);
259    }
260
261    @Override
262    public int getMaxTransceiveLength(int technology) {
263        switch (technology) {
264            case (TagTechnology.NFC_A):
265            case (TagTechnology.MIFARE_CLASSIC):
266            case (TagTechnology.MIFARE_ULTRALIGHT):
267                return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
268            case (TagTechnology.NFC_B):
269                /////////////////////////////////////////////////////////////////
270                // Broadcom: Since BCM2079x supports this, set NfcB max size.
271                //return 0; // PN544 does not support transceive of raw NfcB
272                return 253; // PN544 does not support transceive of raw NfcB
273            case (TagTechnology.NFC_V):
274                return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
275            case (TagTechnology.ISO_DEP):
276                /* The maximum length of a normal IsoDep frame consists of:
277                 * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes
278                 * such a frame is supported. Extended length frames however
279                 * are not supported.
280                 */
281                return 261; // Will be automatically split in two frames on the RF layer
282            case (TagTechnology.NFC_F):
283                return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC
284            default:
285                return 0;
286        }
287
288    }
289
290    private native void doSetP2pInitiatorModes(int modes);
291    @Override
292    public void setP2pInitiatorModes(int modes) {
293        doSetP2pInitiatorModes(modes);
294    }
295
296    private native void doSetP2pTargetModes(int modes);
297    @Override
298    public void setP2pTargetModes(int modes) {
299        doSetP2pTargetModes(modes);
300    }
301
302    @Override
303    public boolean getExtendedLengthApdusSupported() {
304        // TODO check BCM support
305        return false;
306    }
307
308    @Override
309    public boolean enablePN544Quirks() {
310        return false;
311    }
312
313    @Override
314    public byte[][] getWipeApdus() {
315        return EE_WIPE_APDUS;
316    }
317
318    @Override
319    public int getDefaultLlcpMiu() {
320        return DEFAULT_LLCP_MIU;
321    }
322
323    @Override
324    public int getDefaultLlcpRwSize() {
325        return DEFAULT_LLCP_RWSIZE;
326    }
327
328    private native String doDump();
329    @Override
330    public String dump() {
331        return doDump();
332    }
333
334    private native void doEnableReaderMode(int technologies);
335    @Override
336    public boolean enableReaderMode(int technologies) {
337        doEnableReaderMode(technologies);
338        return true;
339    }
340
341    private native void doDisableReaderMode();
342    @Override
343    public boolean disableReaderMode() {
344        doDisableReaderMode();
345        return true;
346    }
347
348    private native void doEnableScreenOffSuspend();
349    @Override
350    public boolean enableScreenOffSuspend() {
351        doEnableScreenOffSuspend();
352        return true;
353    }
354
355    private native void doDisableScreenOffSuspend();
356    @Override
357    public boolean disableScreenOffSuspend() {
358        doDisableScreenOffSuspend();
359        return true;
360    }
361
362    /**
363     * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
364     */
365    private void notifyNdefMessageListeners(NativeNfcTag tag) {
366        mListener.onRemoteEndpointDiscovered(tag);
367    }
368
369    /**
370     * Notifies transaction
371     */
372    private void notifyTargetDeselected() {
373        mListener.onCardEmulationDeselected();
374    }
375
376    /**
377     * Notifies transaction
378     */
379    private void notifyTransactionListeners(byte[] aid) {
380        mListener.onCardEmulationAidSelected(aid);
381    }
382
383    /**
384     * Notifies P2P Device detected, to activate LLCP link
385     */
386    private void notifyLlcpLinkActivation(NativeP2pDevice device) {
387        mListener.onLlcpLinkActivated(device);
388    }
389
390    /**
391     * Notifies P2P Device detected, to activate LLCP link
392     */
393    private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
394        mListener.onLlcpLinkDeactivated(device);
395    }
396
397    /**
398     * Notifies first packet received from remote LLCP
399     */
400    private void notifyLlcpLinkFirstPacketReceived(NativeP2pDevice device) {
401        mListener.onLlcpFirstPacketReceived(device);
402    }
403
404    private void notifySeFieldActivated() {
405        mListener.onRemoteFieldActivated();
406    }
407
408    private void notifySeFieldDeactivated() {
409        mListener.onRemoteFieldDeactivated();
410    }
411
412    private void notifySeListenActivated() {
413        mListener.onSeListenActivated();
414    }
415
416    private void notifySeListenDeactivated() {
417        mListener.onSeListenDeactivated();
418    }
419
420    private void notifySeApduReceived(byte[] apdu) {
421        mListener.onSeApduReceived(apdu);
422    }
423
424    private void notifySeEmvCardRemoval() {
425        mListener.onSeEmvCardRemoval();
426    }
427
428    private void notifySeMifareAccess(byte[] block) {
429        mListener.onSeMifareAccess(block);
430    }
431
432    private void notifyHostEmuActivated() {
433        mListener.onHostCardEmulationActivated();
434    }
435
436    private void notifyHostEmuData(byte[] data) {
437        mListener.onHostCardEmulationData(data);
438    }
439
440    private void notifyHostEmuDeactivated() {
441        mListener.onHostCardEmulationDeactivated();
442    }
443
444}
445