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
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    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
60    public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED";
61
62    /* Native structure */
63    private int mNative;
64
65    private final DeviceHostListener mListener;
66    private final Context mContext;
67
68    public NativeNfcManager(Context context, DeviceHostListener listener) {
69        mListener = listener;
70        initializeNativeStructure();
71        mContext = context;
72    }
73
74    public native boolean initializeNativeStructure();
75
76    private native boolean doDownload();
77
78    public native int doGetLastError();
79
80    @Override
81    public void checkFirmware() {
82    }
83
84    private native boolean doInitialize();
85
86    @Override
87    public boolean initialize() {
88        SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
89        SharedPreferences.Editor editor = prefs.edit();
90
91        if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) {
92            try {
93                Thread.sleep (12000);
94                editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
95                editor.apply();
96            } catch (InterruptedException e) { }
97        }
98
99        return doInitialize();
100    }
101
102    private native boolean doDeinitialize();
103
104    @Override
105    public boolean deinitialize() {
106        SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
107        SharedPreferences.Editor editor = prefs.edit();
108
109        editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
110        editor.apply();
111
112        return doDeinitialize();
113    }
114
115    @Override
116    public String getName() {
117        return DRIVER_NAME;
118    }
119
120    @Override
121    public native void enableDiscovery();
122
123    @Override
124    public native void disableDiscovery();
125
126    @Override
127    public native int[] doGetSecureElementList();
128
129    @Override
130    public native void doSelectSecureElement();
131
132    @Override
133    public native void doDeselectSecureElement();
134
135
136    private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap,
137            String sn);
138
139    @Override
140    public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn)
141            throws LlcpException {
142        LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn);
143        if (socket != null) {
144            return socket;
145        } else {
146            /* Get Error Status */
147            int error = doGetLastError();
148
149            Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
150
151            switch (error) {
152                case ErrorCodes.ERROR_BUFFER_TO_SMALL:
153                case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
154                    throw new LlcpException(error);
155                default:
156                    throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
157            }
158        }
159    }
160
161    private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
162            int rw, int linearBufferLength);
163    @Override
164    public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu,
165            int rw, int linearBufferLength) throws LlcpException {
166        LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength);
167        if (socket != null) {
168            return socket;
169        } else {
170            /* Get Error Status */
171            int error = doGetLastError();
172
173            Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
174
175            switch (error) {
176                case ErrorCodes.ERROR_BUFFER_TO_SMALL:
177                case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
178                    throw new LlcpException(error);
179                default:
180                    throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
181            }
182        }
183    }
184
185    private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
186            int linearBufferLength);
187    @Override
188    public LlcpSocket createLlcpSocket(int sap, int miu, int rw,
189            int linearBufferLength) throws LlcpException {
190        LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
191        if (socket != null) {
192            return socket;
193        } else {
194            /* Get Error Status */
195            int error = doGetLastError();
196
197            Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
198
199            switch (error) {
200                case ErrorCodes.ERROR_BUFFER_TO_SMALL:
201                case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
202                    throw new LlcpException(error);
203                default:
204                    throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
205            }
206        }
207    }
208
209    @Override
210    public native boolean doCheckLlcp();
211
212    @Override
213    public native boolean doActivateLlcp();
214
215    private native void doResetTimeouts();
216
217    @Override
218    public void resetTimeouts() {
219        doResetTimeouts();
220    }
221
222    @Override
223    public native void doAbort();
224
225    private native boolean doSetTimeout(int tech, int timeout);
226    @Override
227    public boolean setTimeout(int tech, int timeout) {
228        return doSetTimeout(tech, timeout);
229    }
230
231    private native int doGetTimeout(int tech);
232    @Override
233    public int getTimeout(int tech) {
234        return doGetTimeout(tech);
235    }
236
237
238    @Override
239    public boolean canMakeReadOnly(int ndefType) {
240        return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2);
241    }
242
243    @Override
244    public int getMaxTransceiveLength(int technology) {
245        switch (technology) {
246            case (TagTechnology.NFC_A):
247            case (TagTechnology.MIFARE_CLASSIC):
248            case (TagTechnology.MIFARE_ULTRALIGHT):
249                return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
250            case (TagTechnology.NFC_B):
251                /////////////////////////////////////////////////////////////////
252                // Broadcom: Since BCM2079x supports this, set NfcB max size.
253                //return 0; // PN544 does not support transceive of raw NfcB
254                return 253; // PN544 does not support transceive of raw NfcB
255            case (TagTechnology.NFC_V):
256                return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
257            case (TagTechnology.ISO_DEP):
258                /* The maximum length of a normal IsoDep frame consists of:
259                 * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes
260                 * such a frame is supported. Extended length frames however
261                 * are not supported.
262                 */
263                return 261; // Will be automatically split in two frames on the RF layer
264            case (TagTechnology.NFC_F):
265                return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC
266            default:
267                return 0;
268        }
269
270    }
271
272    private native void doSetP2pInitiatorModes(int modes);
273    @Override
274    public void setP2pInitiatorModes(int modes) {
275        doSetP2pInitiatorModes(modes);
276    }
277
278    private native void doSetP2pTargetModes(int modes);
279    @Override
280    public void setP2pTargetModes(int modes) {
281        doSetP2pTargetModes(modes);
282    }
283    @Override
284    public boolean getExtendedLengthApdusSupported() {
285        // TODO check BCM support
286        return false;
287    }
288
289    @Override
290    public boolean enablePN544Quirks() {
291        return false;
292    }
293
294    @Override
295    public byte[][] getWipeApdus() {
296        return EE_WIPE_APDUS;
297    }
298
299    @Override
300    public int getDefaultLlcpMiu() {
301        return DEFAULT_LLCP_MIU;
302    }
303
304    @Override
305    public int getDefaultLlcpRwSize() {
306        return DEFAULT_LLCP_RWSIZE;
307    }
308
309    private native String doDump();
310    @Override
311    public String dump() {
312        return doDump();
313    }
314
315    /**
316     * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
317     */
318    private void notifyNdefMessageListeners(NativeNfcTag tag) {
319        mListener.onRemoteEndpointDiscovered(tag);
320    }
321
322    /**
323     * Notifies transaction
324     */
325    private void notifyTargetDeselected() {
326        mListener.onCardEmulationDeselected();
327    }
328
329    /**
330     * Notifies transaction
331     */
332    private void notifyTransactionListeners(byte[] aid) {
333        mListener.onCardEmulationAidSelected(aid);
334    }
335
336    /**
337     * Notifies P2P Device detected, to activate LLCP link
338     */
339    private void notifyLlcpLinkActivation(NativeP2pDevice device) {
340        mListener.onLlcpLinkActivated(device);
341    }
342
343    /**
344     * Notifies P2P Device detected, to activate LLCP link
345     */
346    private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
347        mListener.onLlcpLinkDeactivated(device);
348    }
349
350    private void notifySeFieldActivated() {
351        mListener.onRemoteFieldActivated();
352    }
353
354    private void notifySeFieldDeactivated() {
355        mListener.onRemoteFieldDeactivated();
356    }
357
358    private void notifySeListenActivated() {
359        mListener.onSeListenActivated();
360    }
361
362    private void notifySeListenDeactivated() {
363        mListener.onSeListenDeactivated();
364    }
365
366    private void notifySeApduReceived(byte[] apdu) {
367        mListener.onSeApduReceived(apdu);
368    }
369
370    private void notifySeEmvCardRemoval() {
371        mListener.onSeEmvCardRemoval();
372    }
373
374    private void notifySeMifareAccess(byte[] block) {
375        mListener.onSeMifareAccess(block);
376    }
377
378}
379