• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static com.android.nfc.NfcStatsLog.NFC_PROPRIETARY_CAPABILITIES_REPORTED__PASSIVE_OBSERVE_MODE__MODE_UNKNOWN;
20 import static com.android.nfc.NfcStatsLog.NFC_PROPRIETARY_CAPABILITIES_REPORTED__PASSIVE_OBSERVE_MODE__SUPPORT_WITHOUT_RF_DEACTIVATION;
21 import static com.android.nfc.NfcStatsLog.NFC_PROPRIETARY_CAPABILITIES_REPORTED__PASSIVE_OBSERVE_MODE__SUPPORT_WITH_RF_DEACTIVATION;
22 
23 import android.content.Context;
24 import android.nfc.cardemulation.PollingFrame;
25 import android.nfc.tech.Ndef;
26 import android.nfc.tech.TagTechnology;
27 import android.os.Bundle;
28 import android.os.Trace;
29 import android.sysprop.NfcProperties;
30 import android.util.Log;
31 
32 import com.android.nfc.DeviceHost;
33 import com.android.nfc.ExitFrame;
34 import com.android.nfc.NfcDiscoveryParameters;
35 import com.android.nfc.NfcProprietaryCaps;
36 import com.android.nfc.NfcService;
37 import com.android.nfc.NfcStatsLog;
38 import com.android.nfc.NfcVendorNciResponse;
39 
40 import java.io.FileDescriptor;
41 import java.io.PrintWriter;
42 import java.nio.ByteBuffer;
43 import java.nio.ByteOrder;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.HashMap;
47 import java.util.HexFormat;
48 import java.util.Iterator;
49 import java.util.Map;
50 
51 /** Native interface to the NFC Manager functions */
52 public class NativeNfcManager implements DeviceHost {
53     private static final String TAG = "NativeNfcManager";
54     static final String PREF = "NciDeviceHost";
55 
56     static final String DRIVER_NAME = "android-nci";
57 
58     /* Native structure */
59     private long mNative;
60 
61     private int mIsoDepMaxTransceiveLength;
62     private final DeviceHostListener mListener;
63     private final NativeT4tNfceeManager mT4tNfceeMgr;
64     private final Context mContext;
65 
66     private final Object mLock = new Object();
67     private final HashMap<Integer, byte[]> mT3tIdentifiers = new HashMap<Integer, byte[]>();
68     private NfcProprietaryCaps mProprietaryCaps = null;
69     private static final int MIN_POLLING_FRAME_TLV_SIZE = 5;
70     private static final int TAG_FIELD_CHANGE = 0;
71     private static final int TAG_NFC_A = 1;
72     private static final int TAG_NFC_B = 2;
73     private static final int TAG_NFC_F = 3;
74     private static final int TAG_NFC_UNKNOWN = 7;
75     private static final int NCI_HEADER_MIN_LEN = 3;
76     private static final int NCI_GID_INDEX = 0;
77     private static final int NCI_OID_INDEX = 1;
78     private static final int OP_CODE_INDEX = 3;
79 
80     private static final int OBSERVE_MODE_SUSPENDED_FRAME_TYPE_A = 0x00;
81     private static final int OBSERVE_MODE_SUSPENDED_FRAME_TYPE_B = 0x01;
82 
loadLibrary()83     private void loadLibrary() {
84         System.loadLibrary("nfc_nci_jni");
85     }
86 
87     private static NativeNfcManager sInstance;
88 
getInstance()89     public static NativeNfcManager getInstance() {
90         if (sInstance == null) throw new IllegalStateException("NativeNfcManager instance null");
91         return sInstance;
92     }
93 
NativeNfcManager(Context context, DeviceHostListener listener)94     public NativeNfcManager(Context context, DeviceHostListener listener) {
95         mListener = listener;
96         loadLibrary();
97         initializeNativeStructure();
98         mContext = context;
99         mT4tNfceeMgr = new NativeT4tNfceeManager();
100         sInstance = this;
101     }
102 
initializeNativeStructure()103     public native boolean initializeNativeStructure();
104 
doDownload()105     private native boolean doDownload();
106 
107     @Override
checkFirmware()108     public boolean checkFirmware() {
109         return doDownload();
110     }
111 
doInitialize()112     private native boolean doInitialize();
113 
getIsoDepMaxTransceiveLength()114     private native int getIsoDepMaxTransceiveLength();
115 
116     @Override
initialize()117     public boolean initialize() {
118         boolean ret = doInitialize();
119         if (ret && isProprietaryGetCapsSupported()) {
120             mProprietaryCaps = NfcProprietaryCaps.createFromByteArray(getProprietaryCaps());
121             Log.i(TAG, "initialize: mProprietaryCaps: " + mProprietaryCaps);
122             logProprietaryCaps(mProprietaryCaps);
123         }
124         mIsoDepMaxTransceiveLength = getIsoDepMaxTransceiveLength();
125         return ret;
126     }
127 
isObserveModeSupportedWithoutRfDeactivation()128     boolean isObserveModeSupportedWithoutRfDeactivation() {
129         if (!com.android.nfc.flags.Flags.observeModeWithoutRf()) {
130             return false;
131         }
132         return mProprietaryCaps != null &&
133                 mProprietaryCaps.getPassiveObserveMode() ==
134                         NfcProprietaryCaps.PassiveObserveMode.SUPPORT_WITHOUT_RF_DEACTIVATION;
135     }
136 
doSetPartialInitMode(int mode)137     private native void doSetPartialInitMode(int mode);
138 
139     @Override
setPartialInitMode(int mode)140     public void setPartialInitMode(int mode) {
141         doSetPartialInitMode(mode);
142     }
143 
doEnableDtaMode()144     private native void doEnableDtaMode();
145 
146     @Override
enableDtaMode()147     public void enableDtaMode() {
148         doEnableDtaMode();
149     }
150 
doDisableDtaMode()151     private native void doDisableDtaMode();
152 
153     @Override
disableDtaMode()154     public void disableDtaMode() {
155         Log.d(TAG, "disableDtaMode:");
156         doDisableDtaMode();
157     }
158 
doFactoryReset()159     private native void doFactoryReset();
160 
161     @Override
factoryReset()162     public void factoryReset() {
163         doFactoryReset();
164     }
165 
doSetPowerSavingMode(boolean flag)166     private native boolean doSetPowerSavingMode(boolean flag);
167 
168     @Override
setPowerSavingMode(boolean flag)169     public boolean setPowerSavingMode(boolean flag) {
170         return doSetPowerSavingMode(flag);
171     }
172 
doShutdown()173     private native void doShutdown();
174 
175     @Override
shutdown()176     public void shutdown() {
177         doShutdown();
178     }
179 
doDeinitialize()180     private native boolean doDeinitialize();
181 
182     @Override
deinitialize()183     public boolean deinitialize() {
184         return doDeinitialize();
185     }
186 
187     @Override
getName()188     public String getName() {
189         return DRIVER_NAME;
190     }
191 
192     @Override
sendRawFrame(byte[] data)193     public native boolean sendRawFrame(byte[] data);
194 
195     @Override
routeAid(byte[] aid, int route, int aidInfo, int power)196     public native boolean routeAid(byte[] aid, int route, int aidInfo, int power);
197 
198     @Override
unrouteAid(byte[] aid)199     public native boolean unrouteAid(byte[] aid);
200 
201     @Override
commitRouting()202     public native int commitRouting();
203 
doRegisterT3tIdentifier(byte[] t3tIdentifier)204     public native int doRegisterT3tIdentifier(byte[] t3tIdentifier);
205 
206     /**
207      * Injects a NTF to the HAL.
208      *
209      * This is only used for testing.
210      */
injectNtf(byte[] data)211     public native void injectNtf(byte[] data);
212 
isProprietaryGetCapsSupported()213     public boolean isProprietaryGetCapsSupported() {
214         return mContext.getResources()
215                 .getBoolean(com.android.nfc.R.bool.nfc_proprietary_getcaps_supported)
216                 && NfcProperties.get_caps_supported().orElse(true);
217     }
218 
219     @Override
isObserveModeSupported()220     public boolean isObserveModeSupported() {
221         // Check if the device overlay and HAL capabilities indicate that observe
222         // mode is supported.
223         if (!mContext.getResources().getBoolean(
224                 com.android.nfc.R.bool.nfc_observe_mode_supported)) {
225             return false;
226         }
227         if (!NfcProperties.observe_mode_supported().orElse(true)) {
228             return false;
229         }
230         if (com.android.nfc.flags.Flags.observeModeWithoutRf()) {
231             if (isProprietaryGetCapsSupported()) {
232                 return isObserveModeSupportedWithoutRfDeactivation();
233             }
234             return false;
235         } else {
236             if (isProprietaryGetCapsSupported()) {
237                 return isObserveModeSupportedCaps(mProprietaryCaps);
238             }
239             return true;
240         }
241     }
242 
243     @Override
isFirmwareExitFramesSupported()244     public boolean isFirmwareExitFramesSupported() {
245         if (!com.android.nfc.flags.Flags.exitFrames()) {
246             return false;
247         }
248         if (isProprietaryGetCapsSupported()) {
249             return mProprietaryCaps != null
250                     && mProprietaryCaps.isAutotransactPollingLoopFilterSupported()
251                     && mProprietaryCaps.getNumberOfExitFramesSupported() > 0;
252         }
253         return false;
254     }
255 
256     @Override
setObserveMode(boolean enabled)257     public native boolean setObserveMode(boolean enabled);
258 
259     @Override
isObserveModeEnabled()260     public native boolean isObserveModeEnabled();
261 
262     @Override
getNumberOfFirmwareExitFramesSupported()263     public int getNumberOfFirmwareExitFramesSupported() {
264         return mProprietaryCaps != null ? mProprietaryCaps.getNumberOfExitFramesSupported() : -1;
265     }
266 
267     @Override
setFirmwareExitFrameTable(ExitFrame[] exitFrames, byte[] timeoutMs)268     public native boolean setFirmwareExitFrameTable(ExitFrame[] exitFrames, byte[] timeoutMs);
269 
270     @Override
getT4TNfceePowerState()271     public int   getT4TNfceePowerState() {
272         return mT4tNfceeMgr.getT4TNfceePowerState();
273     }
274 
275     @Override
getNdefNfceeRouteId()276     public int getNdefNfceeRouteId() {
277         return mT4tNfceeMgr.getNdefNfceeRouteId();
278     }
279 
280     @Override
isNdefNfceefeatureEnabled()281     public boolean isNdefNfceefeatureEnabled() {
282         return mT4tNfceeMgr.isNdefNfceefeatureEnabled();
283     }
284 
285     @Override
doWriteData(byte[] fileId, byte[] data)286     public int doWriteData(byte[] fileId, byte[] data) {
287         return mT4tNfceeMgr.doWriteData(fileId, data);
288     }
289 
290     @Override
doReadData(byte[] fileId)291     public byte[] doReadData(byte[] fileId) {
292         return mT4tNfceeMgr.doReadData(fileId);
293     }
294 
295     @Override
doClearNdefData()296     public boolean doClearNdefData() {
297         return mT4tNfceeMgr.doClearNdefData();
298     }
299 
300     @Override
isNdefOperationOngoing()301     public boolean isNdefOperationOngoing() {
302         return mT4tNfceeMgr.isNdefOperationOngoing();
303     }
304 
305     @Override
isNdefNfceeEmulationSupported()306     public boolean isNdefNfceeEmulationSupported() {
307         return mT4tNfceeMgr.isNdefNfceeEmulationSupported();
308     }
309 
310     @Override
registerT3tIdentifier(byte[] t3tIdentifier)311     public void registerT3tIdentifier(byte[] t3tIdentifier) {
312         synchronized (mLock) {
313             int handle = doRegisterT3tIdentifier(t3tIdentifier);
314             if (handle != 0xffff) {
315                 mT3tIdentifiers.put(Integer.valueOf(handle), t3tIdentifier);
316             }
317         }
318     }
319 
doDeregisterT3tIdentifier(int handle)320     public native void doDeregisterT3tIdentifier(int handle);
321 
322     @Override
deregisterT3tIdentifier(byte[] t3tIdentifier)323     public void deregisterT3tIdentifier(byte[] t3tIdentifier) {
324         synchronized (mLock) {
325             Iterator<Integer> it = mT3tIdentifiers.keySet().iterator();
326             while (it.hasNext()) {
327                 int handle = it.next().intValue();
328                 byte[] value = mT3tIdentifiers.get(handle);
329                 if (Arrays.equals(value, t3tIdentifier)) {
330                     doDeregisterT3tIdentifier(handle);
331                     mT3tIdentifiers.remove(handle);
332                     break;
333                 }
334             }
335         }
336     }
337 
338     @Override
clearT3tIdentifiersCache()339     public void clearT3tIdentifiersCache() {
340         synchronized (mLock) {
341             mT3tIdentifiers.clear();
342         }
343     }
344 
345     @Override
getLfT3tMax()346     public native int getLfT3tMax();
347 
348     @Override
doSetScreenState(int screen_state_mask, boolean alwaysPoll)349     public native void doSetScreenState(int screen_state_mask, boolean alwaysPoll);
350 
351     @Override
getNciVersion()352     public native int getNciVersion();
353 
doEnableDiscovery( int techMask, boolean enableLowPowerPolling, boolean enableReaderMode, boolean enableHostRouting, byte[] techAPollingLoopAnnotation, boolean restart)354     private native void doEnableDiscovery(
355             int techMask,
356             boolean enableLowPowerPolling,
357             boolean enableReaderMode,
358             boolean enableHostRouting,
359             byte[] techAPollingLoopAnnotation,
360             boolean restart);
361 
362 
363     @Override
enableDiscovery(NfcDiscoveryParameters params, boolean restart)364     public void enableDiscovery(NfcDiscoveryParameters params, boolean restart) {
365         doEnableDiscovery(
366                 params.getTechMask(),
367                 params.shouldEnableLowPowerDiscovery(),
368                 params.shouldEnableReaderMode(),
369                 params.shouldEnableHostRouting(),
370                 params.techAPollingLoopAnnotation(),
371                 restart);
372     }
373 
374     @Override
disableDiscovery()375     public native void disableDiscovery();
376 
doResetTimeouts()377     private native void doResetTimeouts();
378 
379     @Override
resetTimeouts()380     public void resetTimeouts() {
381         doResetTimeouts();
382     }
383 
384     @Override
doAbort(String msg)385     public native void doAbort(String msg);
386 
doSetTimeout(int tech, int timeout)387     private native boolean doSetTimeout(int tech, int timeout);
388 
389     @Override
setTimeout(int tech, int timeout)390     public boolean setTimeout(int tech, int timeout) {
391         return doSetTimeout(tech, timeout);
392     }
393 
doGetTimeout(int tech)394     private native int doGetTimeout(int tech);
395 
396     @Override
getTimeout(int tech)397     public int getTimeout(int tech) {
398         return doGetTimeout(tech);
399     }
400 
401     @Override
canMakeReadOnly(int ndefType)402     public boolean canMakeReadOnly(int ndefType) {
403         return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2);
404     }
405 
406     @Override
getMaxTransceiveLength(int technology)407     public int getMaxTransceiveLength(int technology) {
408         switch (technology) {
409             case (TagTechnology.NFC_A):
410             case (TagTechnology.MIFARE_CLASSIC):
411             case (TagTechnology.MIFARE_ULTRALIGHT):
412                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
413             case (TagTechnology.NFC_B):
414                 /////////////////////////////////////////////////////////////////
415                 // Broadcom: Since BCM2079x supports this, set NfcB max size.
416                 // return 0; // PN544 does not support transceive of raw NfcB
417                 return 253; // PN544 does not support transceive of raw NfcB
418             case (TagTechnology.NFC_V):
419                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
420             case (TagTechnology.ISO_DEP):
421                 return mIsoDepMaxTransceiveLength;
422             case (TagTechnology.NFC_F):
423                 return 255;
424             default:
425                 return 0;
426         }
427     }
428 
getAidTableSize()429     public native int getAidTableSize();
430 
431     @Override
getExtendedLengthApdusSupported()432     public boolean getExtendedLengthApdusSupported() {
433         /* 261 is the default size if extended length frames aren't supported */
434         if (getMaxTransceiveLength(TagTechnology.ISO_DEP) > 261) return true;
435         return false;
436     }
437 
doDump(FileDescriptor fd)438     private native void doDump(FileDescriptor fd);
439 
440     @Override
dump(PrintWriter pw, FileDescriptor fd)441     public void dump(PrintWriter pw, FileDescriptor fd) {
442         pw.println("Native Proprietary Caps=" + mProprietaryCaps);
443         doDump(fd);
444     }
445 
doRestartRfDiscovery()446     private native void doRestartRfDiscovery();
447 
448     @Override
restartRfDiscovery()449     public void restartRfDiscovery() {
450         doRestartRfDiscovery();
451     }
452 
doSetNfcSecure(boolean enable)453     private native boolean doSetNfcSecure(boolean enable);
454 
455     @Override
setNfcSecure(boolean enable)456     public boolean setNfcSecure(boolean enable) {
457         return doSetNfcSecure(enable);
458     }
459 
doStartStopPolling(boolean start)460     private native void doStartStopPolling(boolean start);
461 
462     @Override
startStopPolling(boolean start)463     public void startStopPolling(boolean start) {
464         doStartStopPolling(start);
465     }
466 
doSetNfceePowerAndLinkCtrl(boolean enable)467     private native void doSetNfceePowerAndLinkCtrl(boolean enable);
468 
469     @Override
setNfceePowerAndLinkCtrl(boolean enable)470     public void setNfceePowerAndLinkCtrl(boolean enable) {
471         doSetNfceePowerAndLinkCtrl(enable);
472     }
473 
474     @Override
getRoutingTable()475     public native byte[] getRoutingTable();
476 
477     @Override
getMaxRoutingTableSize()478     public native int getMaxRoutingTableSize();
479 
isMultiTag()480     public native boolean isMultiTag();
481 
482     @Override
dofetchActiveNfceeList()483     public native Map<String, Integer> dofetchActiveNfceeList();
484 
nativeSendRawVendorCmd( int mt, int gid, int oid, byte[] payload)485     private native NfcVendorNciResponse nativeSendRawVendorCmd(
486             int mt, int gid, int oid, byte[] payload);
487 
488     @Override
sendRawVendorCmd(int mt, int gid, int oid, byte[] payload)489     public NfcVendorNciResponse sendRawVendorCmd(int mt, int gid, int oid, byte[] payload) {
490         NfcVendorNciResponse res= nativeSendRawVendorCmd(mt, gid, oid, payload);
491         return res;
492     }
493 
494     /** Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) */
notifyNdefMessageListeners(NativeNfcTag tag)495     private void notifyNdefMessageListeners(NativeNfcTag tag) {
496         mListener.onRemoteEndpointDiscovered(tag);
497     }
498 
notifyHostEmuActivated(int technology)499     private void notifyHostEmuActivated(int technology) {
500         mListener.onHostCardEmulationActivated(technology);
501     }
502 
notifyHostEmuData(int technology, byte[] data)503     private void notifyHostEmuData(int technology, byte[] data) {
504         mListener.onHostCardEmulationData(technology, data);
505     }
506 
notifyHostEmuDeactivated(int technology)507     private void notifyHostEmuDeactivated(int technology) {
508         mListener.onHostCardEmulationDeactivated(technology);
509     }
510 
notifyRfFieldActivated()511     private void notifyRfFieldActivated() {
512         mListener.onRemoteFieldActivated();
513     }
514 
notifyRfFieldDeactivated()515     private void notifyRfFieldDeactivated() {
516         mListener.onRemoteFieldDeactivated();
517     }
518 
notifyTransactionListeners(byte[] aid, byte[] data, String evtSrc)519     private void notifyTransactionListeners(byte[] aid, byte[] data, String evtSrc) {
520         mListener.onNfcTransactionEvent(aid, data, evtSrc);
521     }
522 
notifyEeUpdated()523     private void notifyEeUpdated() {
524         mListener.onEeUpdated();
525     }
526 
notifyHwErrorReported()527     private void notifyHwErrorReported() {
528         mListener.onHwErrorReported();
529     }
530 
notifyEeAidSelected(byte[] aid, String eventSrc)531     private void notifyEeAidSelected(byte[] aid, String eventSrc) {
532         Log.i(TAG, "notifyEeAidSelected: AID= " + HexFormat.of().formatHex(aid) + " selected by "
533                 + eventSrc);
534         if (com.android.nfc.flags.Flags.eeAidSelect()) {
535             mListener.onSeSelected(NfcService.SE_SELECTED_AID);
536         }
537     }
538 
notifyEeProtocolSelected(int protocol, String eventSrc)539     private void notifyEeProtocolSelected(int protocol, String eventSrc) {
540         Log.i(TAG, "notifyEeProtocolSelected: Protocol: " + protocol + " selected by " + eventSrc);
541         if (com.android.nfc.flags.Flags.eeAidSelect()) {
542             mListener.onSeSelected(NfcService.SE_SELECTED_PROTOCOL);
543         }
544     }
545 
notifyEeTechSelected(int tech, String eventSrc)546     private void notifyEeTechSelected(int tech, String eventSrc) {
547         Log.i(TAG, "notifyEeTechSelected: Tech: " + tech + " selected by " + eventSrc);
548         if (com.android.nfc.flags.Flags.eeAidSelect()) {
549             mListener.onSeSelected(NfcService.SE_SELECTED_TECH);
550         }
551     }
552 
notifyPollingLoopFrame(int data_len, byte[] p_data)553     public void notifyPollingLoopFrame(int data_len, byte[] p_data) {
554         if (data_len < MIN_POLLING_FRAME_TLV_SIZE) {
555             return;
556         }
557         Trace.beginSection("notifyPollingLoopFrame");
558         final int header_len = 4;
559         int pos = header_len;
560         final int TLV_header_len = 3;
561         final int TLV_type_offset = 0;
562         final int TLV_len_offset = 2;
563         final int TLV_timestamp_offset = 3;
564         final int TLV_gain_offset = 7;
565         final int TLV_data_offset = 8;
566         ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>();
567         if (data_len >= TLV_header_len) {
568             int tlv_len = Byte.toUnsignedInt(p_data[TLV_len_offset]) + TLV_header_len;
569             if (tlv_len < data_len) {
570                 data_len = tlv_len;
571             }
572         }
573         while (pos + TLV_len_offset < data_len) {
574             @PollingFrame.PollingFrameType int frameType;
575             Bundle frame = new Bundle();
576             int type = p_data[pos + TLV_type_offset];
577             int length = p_data[pos + TLV_len_offset];
578             if (TLV_len_offset + length < TLV_gain_offset) {
579                 Log.e(TAG, "notifyPollingLoopFrame: Length (" + length
580                         + ") is less than a polling frame, dropping.");
581                 break;
582             }
583             if (pos + TLV_header_len + length > data_len) {
584                 // Frame is bigger than buffer.
585                 Log.e(TAG, "notifyPollingLoopFrame: Polling frame data (" + pos + ", " + length
586                         + ") is longer than buffer data length (" + data_len + ").");
587                 break;
588             }
589             switch (type) {
590                 case TAG_FIELD_CHANGE:
591                     frameType = p_data[pos + TLV_data_offset] != 0x00
592                                     ? PollingFrame.POLLING_LOOP_TYPE_ON
593                                     : PollingFrame.POLLING_LOOP_TYPE_OFF;
594                     break;
595                 case TAG_NFC_A:
596                     frameType = PollingFrame.POLLING_LOOP_TYPE_A;
597                     break;
598                 case TAG_NFC_B:
599                     frameType = PollingFrame.POLLING_LOOP_TYPE_B;
600                     break;
601                 case TAG_NFC_F:
602                     frameType = PollingFrame.POLLING_LOOP_TYPE_F;
603                     break;
604                 case TAG_NFC_UNKNOWN:
605                     frameType = PollingFrame.POLLING_LOOP_TYPE_UNKNOWN;
606                     break;
607                 default:
608                     Log.e(TAG, "notifyPollingLoopFrame: Unknown polling loop tag type.");
609                     return;
610             }
611             byte[] frameData = null;
612             if (pos + TLV_header_len + length <= data_len) {
613                 frameData = Arrays.copyOfRange(p_data, pos + TLV_data_offset,
614                     pos + TLV_header_len + length);
615             }
616             int gain = -1;
617             if (pos + TLV_gain_offset <= data_len) {
618                 gain = Byte.toUnsignedInt(p_data[pos + TLV_gain_offset]);
619                 if (gain == 0XFF) {
620                     gain = -1;
621                 }
622             }
623             long timestamp = 0;
624             if (pos + TLV_timestamp_offset + 3 < data_len) {
625                 timestamp = Integer.toUnsignedLong(ByteBuffer.wrap(p_data,
626                         pos + TLV_timestamp_offset, 4).order(ByteOrder.BIG_ENDIAN).getInt());
627             }
628             pos += (TLV_header_len + length);
629             frames.add(new PollingFrame(frameType, frameData, gain, timestamp, false));
630         }
631         mListener.onPollingLoopDetected(frames);
632         Trace.endSection();
633     }
634 
onObserveModeEnabledInFirmware()635     private void onObserveModeEnabledInFirmware() {
636         mListener.onObserveModeEnabledInFirmware();
637     }
638 
onObserveModeDisabledInFirmware(int type, byte[] data)639     private void onObserveModeDisabledInFirmware(int type, byte[] data) {
640         int pollingFrameType = PollingFrame.POLLING_LOOP_TYPE_UNKNOWN;
641         if (type == OBSERVE_MODE_SUSPENDED_FRAME_TYPE_A) {
642             pollingFrameType = PollingFrame.POLLING_LOOP_TYPE_A;
643         } else if (type == OBSERVE_MODE_SUSPENDED_FRAME_TYPE_B) {
644             pollingFrameType = PollingFrame.POLLING_LOOP_TYPE_B;
645         }
646 
647         mListener.onObserveModeDisabledInFirmware(
648                 new PollingFrame(pollingFrameType, data, -1, -1, true));
649     }
650 
doDetectEpRemoval(int waiting_time_int)651     private native boolean doDetectEpRemoval(int waiting_time_int);
652 
653     @Override
detectEpRemoval(int waiting_time_int)654     public boolean detectEpRemoval(int waiting_time_int) {
655         return doDetectEpRemoval(waiting_time_int);
656     }
657 
notifyWlcStopped(int wpt_end_condition)658     private void notifyWlcStopped(int wpt_end_condition) {
659         mListener.onWlcStopped(wpt_end_condition);
660     }
notifyTagDiscovered(boolean discovered)661     private void notifyTagDiscovered(boolean discovered) {
662         mListener.onTagRfDiscovered(discovered);
663     }
notifyVendorSpecificEvent(int event, int dataLen, byte[] pData)664     private void notifyVendorSpecificEvent(int event, int dataLen, byte[] pData) {
665         if (pData.length < NCI_HEADER_MIN_LEN || dataLen != pData.length) {
666             Log.e(TAG, "notifyVendorSpecificEvent: Invalid data");
667             return;
668         }
669         if (android.nfc.Flags.nfcVendorCmd()) {
670             mListener.onVendorSpecificEvent(pData[NCI_GID_INDEX], pData[NCI_OID_INDEX],
671                     Arrays.copyOfRange(pData, OP_CODE_INDEX, pData.length));
672         }
673     }
674 
notifyRFDiscoveryEvent(boolean isDiscoveryStarted)675     private void notifyRFDiscoveryEvent(boolean isDiscoveryStarted) {
676         mListener.onRfDiscoveryEvent(isDiscoveryStarted);
677     }
678 
notifyEeListenActivated(boolean isActivated)679     private void notifyEeListenActivated(boolean isActivated) {
680         mListener.onEeListenActivated(isActivated);
681     }
682 
683     @Override
setDiscoveryTech(int pollTech, int listenTech)684     public native void setDiscoveryTech(int pollTech, int listenTech);
685 
686     @Override
resetDiscoveryTech()687     public native void resetDiscoveryTech();
688 
689     @Override
clearRoutingEntry(int clearFlags)690     public native void clearRoutingEntry(int clearFlags);
691 
692     @Override
setIsoDepProtocolRoute(int route)693     public native void setIsoDepProtocolRoute(int route);
694 
695     @Override
setTechnologyABFRoute(int route, int felicaRoute)696     public native void setTechnologyABFRoute(int route, int felicaRoute);
697 
698     @Override
setSystemCodeRoute(int route)699     public native void setSystemCodeRoute(int route);
700 
getProprietaryCaps()701     private native byte[] getProprietaryCaps();
702 
703     @Override
enableVendorNciNotifications(boolean enabled)704     public native void enableVendorNciNotifications(boolean enabled);
705 
notifyCommandTimeout()706     private void notifyCommandTimeout() {
707         if (android.nfc.Flags.nfcEventListener()) {
708             mListener.onCommandTimeout();
709         }
710         NfcService.getInstance().storeNativeCrashLogs();
711     }
712 
713     /** wrappers for values */
714     private static final int CAPS_OBSERVE_MODE_UNKNOWN =
715             NFC_PROPRIETARY_CAPABILITIES_REPORTED__PASSIVE_OBSERVE_MODE__MODE_UNKNOWN;
716     private static final int CAPS_OBSERVE_MODE_SUPPORT_WITH_RF_DEACTIVATION =
717           NFC_PROPRIETARY_CAPABILITIES_REPORTED__PASSIVE_OBSERVE_MODE__SUPPORT_WITH_RF_DEACTIVATION;
718     private static final int CAPS_OBSERVE_MODE_SUPPORT_WITHOUT_RF_DEACTIVATION =
719        NFC_PROPRIETARY_CAPABILITIES_REPORTED__PASSIVE_OBSERVE_MODE__SUPPORT_WITHOUT_RF_DEACTIVATION;
720     private static final int CAPS_OBSERVE_MODE_NOT_SUPPORTED =
721             NfcStatsLog.NFC_PROPRIETARY_CAPABILITIES_REPORTED__PASSIVE_OBSERVE_MODE__NOT_SUPPORTED;
722 
isObserveModeSupportedCaps(NfcProprietaryCaps proprietaryCaps)723     private static boolean isObserveModeSupportedCaps(NfcProprietaryCaps proprietaryCaps) {
724         return proprietaryCaps.getPassiveObserveMode()
725             != NfcProprietaryCaps.PassiveObserveMode.NOT_SUPPORTED;
726     }
727 
isReaderModeAnnotationSupportedCaps()728     private  boolean isReaderModeAnnotationSupportedCaps() {
729         return mProprietaryCaps != null && mProprietaryCaps.isReaderModeAnnotationSupported();
730     }
731 
732     @Override
isReaderModeAnnotationSupported()733     public  boolean isReaderModeAnnotationSupported() {
734         return isReaderModeAnnotationSupportedCaps();
735     }
736 
logProprietaryCaps(NfcProprietaryCaps proprietaryCaps)737     private static void logProprietaryCaps(NfcProprietaryCaps proprietaryCaps) {
738         int observeModeStatsd = CAPS_OBSERVE_MODE_UNKNOWN;
739 
740         NfcProprietaryCaps.PassiveObserveMode mode = proprietaryCaps.getPassiveObserveMode();
741 
742         if (mode == NfcProprietaryCaps.PassiveObserveMode.SUPPORT_WITH_RF_DEACTIVATION) {
743             observeModeStatsd = CAPS_OBSERVE_MODE_SUPPORT_WITH_RF_DEACTIVATION;
744         } else if (mode == NfcProprietaryCaps.PassiveObserveMode.SUPPORT_WITHOUT_RF_DEACTIVATION) {
745             observeModeStatsd = CAPS_OBSERVE_MODE_SUPPORT_WITHOUT_RF_DEACTIVATION;
746         } else if (mode == NfcProprietaryCaps.PassiveObserveMode.NOT_SUPPORTED) {
747             observeModeStatsd = CAPS_OBSERVE_MODE_NOT_SUPPORTED;
748         }
749 
750         NfcStatsLog.write(NfcStatsLog.NFC_PROPRIETARY_CAPABILITIES_REPORTED,
751                 observeModeStatsd,
752                 proprietaryCaps.isPollingFrameNotificationSupported(),
753                 proprietaryCaps.isPowerSavingModeSupported(),
754                 proprietaryCaps.isAutotransactPollingLoopFilterSupported(),
755                 proprietaryCaps.getNumberOfExitFramesSupported());
756     }
757 
notifyObserveModeChanged(boolean enabled)758     public void notifyObserveModeChanged(boolean enabled) {
759         mListener.onObserveModeStateChanged(enabled);
760     }
761     /** Notifies remote endpoint removed */
notifyEndpointRemoved(int reason)762     private void notifyEndpointRemoved(int reason) {
763         mListener.onEndpointRemoved(reason);
764 
765     }
766 
767     @Override
isRemovalDetectionInPollModeSupported()768     public native boolean isRemovalDetectionInPollModeSupported();
769 
onRestartRfDiscovery()770     public void onRestartRfDiscovery() {
771         mListener.onRestartRfDiscovery();
772     }
773 }
774