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.nxp;
18
19import com.android.nfc.DeviceHost;
20import com.android.nfc.LlcpException;
21import com.android.nfc.NfcService;
22
23import android.annotation.SdkConstant;
24import android.annotation.SdkConstant.SdkConstantType;
25import android.content.Context;
26import android.content.SharedPreferences;
27import android.nfc.ErrorCodes;
28import android.nfc.tech.Ndef;
29import android.nfc.tech.TagTechnology;
30import android.util.Log;
31
32import java.io.File;
33
34/**
35 * Native interface to the NFC Manager functions
36 */
37public class NativeNfcManager implements DeviceHost {
38    private static final String TAG = "NativeNfcManager";
39
40    private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so";
41
42    private static final String PREF = "NxpDeviceHost";
43
44    private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime";
45    private static final long FIRMWARE_MODTIME_DEFAULT = -1;
46
47    static {
48        System.loadLibrary("nfc_jni");
49    }
50
51    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
52    public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED";
53
54    /* Native structure */
55    private int mNative;
56
57    private final DeviceHostListener mListener;
58    private final Context mContext;
59
60    public NativeNfcManager(Context context, DeviceHostListener listener) {
61        mListener = listener;
62        initializeNativeStructure();
63        mContext = context;
64    }
65
66    public native boolean initializeNativeStructure();
67
68    private native boolean doDownload();
69
70    @Override
71    public void checkFirmware() {
72        // Check that the NFC controller firmware is up to date.  This
73        // ensures that firmware updates are applied in a timely fashion,
74        // and makes it much less likely that the user will have to wait
75        // for a firmware download when they enable NFC in the settings
76        // app.  Firmware download can take some time, so this should be
77        // run in a separate thread.
78
79        // check the timestamp of the firmware file
80        File firmwareFile;
81        int nbRetry = 0;
82        try {
83            firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME);
84        } catch(NullPointerException npe) {
85            Log.e(TAG,"path to firmware file was null");
86            return;
87        }
88
89        long modtime = firmwareFile.lastModified();
90
91        SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
92        long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT);
93        Log.d(TAG,"prev modtime: " + prev_fw_modtime);
94        Log.d(TAG,"new modtime: " + modtime);
95        if (prev_fw_modtime == modtime) {
96            return;
97        }
98
99        // FW download.
100        while(nbRetry < 5) {
101            Log.d(TAG,"Perform Download");
102            if(doDownload()) {
103                Log.d(TAG,"Download Success");
104                // Now that we've finished updating the firmware, save the new modtime.
105                prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply();
106                break;
107            } else {
108                Log.d(TAG,"Download Failed");
109                nbRetry++;
110            }
111        }
112    }
113
114    @Override
115    public native boolean initialize();
116
117    @Override
118    public native boolean deinitialize();
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    @Override
136    public native int doGetLastError();
137
138    private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap);
139
140    private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
141            int rw, int linearBufferLength);
142    @Override
143    public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu,
144            int rw, int linearBufferLength) throws LlcpException {
145        LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength);
146        if (socket != null) {
147            return socket;
148        } else {
149            /* Get Error Status */
150            int error = doGetLastError();
151
152            Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
153
154            switch (error) {
155                case ErrorCodes.ERROR_BUFFER_TO_SMALL:
156                case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
157                    throw new LlcpException(error);
158                default:
159                    throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
160            }
161        }
162    }
163
164    private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
165            int linearBufferLength);
166    @Override
167    public LlcpSocket createLlcpSocket(int sap, int miu, int rw,
168            int linearBufferLength) throws LlcpException {
169        LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
170        if (socket != null) {
171            return socket;
172        } else {
173            /* Get Error Status */
174            int error = doGetLastError();
175
176            Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
177
178            switch (error) {
179                case ErrorCodes.ERROR_BUFFER_TO_SMALL:
180                case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
181                    throw new LlcpException(error);
182                default:
183                    throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
184            }
185        }
186    }
187
188    @Override
189    public native boolean doCheckLlcp();
190
191    @Override
192    public native boolean doActivateLlcp();
193
194    private native void doResetTimeouts();
195
196    @Override
197    public void resetTimeouts() {
198        doResetTimeouts();
199    }
200
201    public native void doAbort();
202
203    private native boolean doSetTimeout(int tech, int timeout);
204    @Override
205    public boolean setTimeout(int tech, int timeout) {
206        return doSetTimeout(tech, timeout);
207    }
208
209    private native int doGetTimeout(int tech);
210    @Override
211    public int getTimeout(int tech) {
212        return doGetTimeout(tech);
213    }
214
215
216    @Override
217    public boolean canMakeReadOnly(int ndefType) {
218        return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2);
219    }
220
221    @Override
222    public int getMaxTransceiveLength(int technology) {
223        switch (technology) {
224            case (TagTechnology.NFC_A):
225            case (TagTechnology.MIFARE_CLASSIC):
226            case (TagTechnology.MIFARE_ULTRALIGHT):
227                return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
228            case (TagTechnology.NFC_B):
229                return 0; // PN544 does not support transceive of raw NfcB
230            case (TagTechnology.NFC_V):
231                return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
232            case (TagTechnology.ISO_DEP):
233                /* The maximum length of a normal IsoDep frame consists of:
234                 * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes
235                 * such a frame is supported. Extended length frames however
236                 * are not supported.
237                 */
238                return 261; // Will be automatically split in two frames on the RF layer
239            case (TagTechnology.NFC_F):
240                return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC
241            default:
242                return 0;
243        }
244
245    }
246
247    private native String doDump();
248    @Override
249    public String dump() {
250        return doDump();
251    }
252
253    /**
254     * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
255     */
256    private void notifyNdefMessageListeners(NativeNfcTag tag) {
257        mListener.onRemoteEndpointDiscovered(tag);
258    }
259
260    /**
261     * Notifies transaction
262     */
263    private void notifyTargetDeselected() {
264        mListener.onCardEmulationDeselected();
265    }
266
267    /**
268     * Notifies transaction
269     */
270    private void notifyTransactionListeners(byte[] aid) {
271        mListener.onCardEmulationAidSelected(aid);
272    }
273
274    /**
275     * Notifies P2P Device detected, to activate LLCP link
276     */
277    private void notifyLlcpLinkActivation(NativeP2pDevice device) {
278        mListener.onLlcpLinkActivated(device);
279    }
280
281    /**
282     * Notifies P2P Device detected, to activate LLCP link
283     */
284    private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
285        mListener.onLlcpLinkDeactivated(device);
286    }
287
288    private void notifySeFieldActivated() {
289        mListener.onRemoteFieldActivated();
290    }
291
292    private void notifySeFieldDeactivated() {
293        mListener.onRemoteFieldDeactivated();
294    }
295
296    private void notifySeApduReceived(byte[] apdu) {
297        mListener.onSeApduReceived(apdu);
298    }
299
300    private void notifySeEmvCardRemoval() {
301        mListener.onSeEmvCardRemoval();
302    }
303
304    private void notifySeMifareAccess(byte[] block) {
305        mListener.onSeMifareAccess(block);
306    }
307}
308