NativeNfcManager.java revision 4bbd47e5507d4c47a4d722216606307e45195a0a
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
31import java.io.File;
32
33/**
34 * Native interface to the NFC Manager functions
35 */
36public class NativeNfcManager implements DeviceHost {
37    private static final String TAG = "NativeNfcManager";
38
39    private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so";
40
41    static final String PREF = "NxpDeviceHost";
42
43    private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime";
44    private static final long FIRMWARE_MODTIME_DEFAULT = -1;
45
46    static {
47        System.loadLibrary("nfc_jni");
48    }
49
50    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
51    public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED";
52
53    /* Native structure */
54    private int mNative;
55
56    private final DeviceHostListener mListener;
57    private final Context mContext;
58
59    public NativeNfcManager(Context context, DeviceHostListener listener) {
60        mListener = listener;
61        initializeNativeStructure();
62        mContext = context;
63    }
64
65    public native boolean initializeNativeStructure();
66
67    private native boolean doDownload();
68
69    public native int doGetLastError();
70
71    @Override
72    public void checkFirmware() {
73        // Check that the NFC controller firmware is up to date.  This
74        // ensures that firmware updates are applied in a timely fashion,
75        // and makes it much less likely that the user will have to wait
76        // for a firmware download when they enable NFC in the settings
77        // app.  Firmware download can take some time, so this should be
78        // run in a separate thread.
79
80        // check the timestamp of the firmware file
81        File firmwareFile;
82        int nbRetry = 0;
83        try {
84            firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME);
85        } catch(NullPointerException npe) {
86            Log.e(TAG,"path to firmware file was null");
87            return;
88        }
89
90        long modtime = firmwareFile.lastModified();
91
92        SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
93        long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT);
94        Log.d(TAG,"prev modtime: " + prev_fw_modtime);
95        Log.d(TAG,"new modtime: " + modtime);
96        if (prev_fw_modtime == modtime) {
97            return;
98        }
99
100        // FW download.
101        while(nbRetry < 5) {
102            Log.d(TAG,"Perform Download");
103            if(doDownload()) {
104                Log.d(TAG,"Download Success");
105                // Now that we've finished updating the firmware, save the new modtime.
106                prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply();
107                break;
108            } else {
109                Log.d(TAG,"Download Failed");
110                nbRetry++;
111            }
112        }
113    }
114
115    private native boolean doInitialize();
116
117    @Override
118    public boolean initialize() {
119        SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
120        SharedPreferences.Editor editor = prefs.edit();
121
122        if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) {
123            try {
124                Thread.sleep (12000);
125                editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
126                editor.apply();
127            } catch (InterruptedException e) { }
128        }
129
130        return doInitialize();
131    }
132
133    private native boolean doDeinitialize();
134
135    @Override
136    public boolean deinitialize() {
137        SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
138        SharedPreferences.Editor editor = prefs.edit();
139
140        editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
141        editor.apply();
142
143        return doDeinitialize();
144    }
145
146    @Override
147    public native void enableDiscovery();
148
149    @Override
150    public native void disableDiscovery();
151
152    @Override
153    public native int[] doGetSecureElementList();
154
155    @Override
156    public native void doSelectSecureElement();
157
158    @Override
159    public native void doDeselectSecureElement();
160
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                ndefType == Ndef.TYPE_MIFARE_CLASSIC);
268    }
269
270    @Override
271    public int getMaxTransceiveLength(int technology) {
272        switch (technology) {
273            case (TagTechnology.NFC_A):
274            case (TagTechnology.MIFARE_CLASSIC):
275            case (TagTechnology.MIFARE_ULTRALIGHT):
276                return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
277            case (TagTechnology.NFC_B):
278                return 0; // PN544 does not support transceive of raw NfcB
279            case (TagTechnology.NFC_V):
280                return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
281            case (TagTechnology.ISO_DEP):
282                /* The maximum length of a normal IsoDep frame consists of:
283                 * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes
284                 * such a frame is supported. Extended length frames however
285                 * are not supported.
286                 */
287                return 261; // Will be automatically split in two frames on the RF layer
288            case (TagTechnology.NFC_F):
289                return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC
290            default:
291                return 0;
292        }
293
294    }
295
296    private native void doSetP2pInitiatorModes(int modes);
297    @Override
298    public void setP2pInitiatorModes(int modes) {
299        doSetP2pInitiatorModes(modes);
300    }
301
302    private native void doSetP2pTargetModes(int modes);
303    @Override
304    public void setP2pTargetModes(int modes) {
305        doSetP2pTargetModes(modes);
306    }
307
308    public boolean getExtendedLengthApdusSupported() {
309        // Not supported on the PN544
310        return false;
311    }
312
313    private native String doDump();
314    @Override
315    public String dump() {
316        return doDump();
317    }
318
319    /**
320     * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
321     */
322    private void notifyNdefMessageListeners(NativeNfcTag tag) {
323        mListener.onRemoteEndpointDiscovered(tag);
324    }
325
326    /**
327     * Notifies transaction
328     */
329    private void notifyTargetDeselected() {
330        mListener.onCardEmulationDeselected();
331    }
332
333    /**
334     * Notifies transaction
335     */
336    private void notifyTransactionListeners(byte[] aid) {
337        mListener.onCardEmulationAidSelected(aid);
338    }
339
340    /**
341     * Notifies P2P Device detected, to activate LLCP link
342     */
343    private void notifyLlcpLinkActivation(NativeP2pDevice device) {
344        mListener.onLlcpLinkActivated(device);
345    }
346
347    /**
348     * Notifies P2P Device detected, to activate LLCP link
349     */
350    private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
351        mListener.onLlcpLinkDeactivated(device);
352    }
353
354    private void notifySeFieldActivated() {
355        mListener.onRemoteFieldActivated();
356    }
357
358    private void notifySeFieldDeactivated() {
359        mListener.onRemoteFieldDeactivated();
360    }
361
362    private void notifySeApduReceived(byte[] apdu) {
363        mListener.onSeApduReceived(apdu);
364    }
365
366    private void notifySeEmvCardRemoval() {
367        mListener.onSeEmvCardRemoval();
368    }
369
370    private void notifySeMifareAccess(byte[] block) {
371        mListener.onSeMifareAccess(block);
372    }
373}
374