react-native-nfc-manager 4.0.0-beta.6 → 4.0.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/README.md +38 -4
  2. package/android/src/main/java/community/revteltech/nfc/MifareClassicHandler.java +419 -0
  3. package/android/src/main/java/community/revteltech/nfc/MifareUltralightHandler.java +84 -0
  4. package/android/src/main/java/community/revteltech/nfc/NdefHandler.java +373 -0
  5. package/android/src/main/java/community/revteltech/nfc/NfcAdapterStateChangedReceiver.java +48 -0
  6. package/android/src/main/java/community/revteltech/nfc/NfcErrorCodes.java +16 -0
  7. package/android/src/main/java/community/revteltech/nfc/NfcManager.java +339 -1125
  8. package/android/src/main/java/community/revteltech/nfc/NfcManagerIOSStubBase.java +130 -0
  9. package/android/src/main/java/community/revteltech/nfc/NfcTechIoRouter.java +258 -0
  10. package/android/src/main/java/community/revteltech/nfc/TagTechnologyRequest.java +19 -7
  11. package/android/src/main/java/community/revteltech/nfc/Util.java +201 -0
  12. package/dist/ndef-lib/constants.js +67 -0
  13. package/dist/ndef-lib/constants.js.map +1 -0
  14. package/dist/ndef-lib/index.js +79 -0
  15. package/dist/ndef-lib/index.js.map +1 -0
  16. package/dist/ndef-lib/ndef-text.js +29 -0
  17. package/dist/ndef-lib/ndef-text.js.map +1 -0
  18. package/dist/ndef-lib/ndef-uri.js +40 -0
  19. package/dist/ndef-lib/ndef-uri.js.map +1 -0
  20. package/dist/ndef-lib/ndef-wifi-simple.js +100 -0
  21. package/dist/ndef-lib/ndef-wifi-simple.js.map +1 -0
  22. package/dist/ndef-lib/ndef.js +153 -0
  23. package/dist/ndef-lib/ndef.js.map +1 -0
  24. package/dist/ndef-lib/stringifier.js +155 -0
  25. package/dist/ndef-lib/stringifier.js.map +1 -0
  26. package/dist/ndef-lib/util.js +126 -0
  27. package/dist/ndef-lib/util.js.map +1 -0
  28. package/dist/specs/NativeNfcManager.js +5 -0
  29. package/dist/specs/NativeNfcManager.js.map +1 -0
  30. package/dist/src/NativeNfcManager.js +55 -0
  31. package/dist/src/NativeNfcManager.js.map +1 -0
  32. package/dist/src/NfcError.js +220 -0
  33. package/dist/src/NfcError.js.map +1 -0
  34. package/dist/src/NfcManager.js +175 -0
  35. package/dist/src/NfcManager.js.map +1 -0
  36. package/dist/src/NfcManagerAndroid.js +112 -0
  37. package/dist/src/NfcManagerAndroid.js.map +1 -0
  38. package/dist/src/NfcManagerIOS.js +119 -0
  39. package/dist/src/NfcManagerIOS.js.map +1 -0
  40. package/dist/src/NfcTech/Iso15693HandlerIOS.js +99 -0
  41. package/dist/src/NfcTech/Iso15693HandlerIOS.js.map +1 -0
  42. package/dist/src/NfcTech/IsoDepHandler.js +29 -0
  43. package/dist/src/NfcTech/IsoDepHandler.js.map +1 -0
  44. package/dist/src/NfcTech/MifareClassicHandlerAndroid.js +68 -0
  45. package/dist/src/NfcTech/MifareClassicHandlerAndroid.js.map +1 -0
  46. package/dist/src/NfcTech/MifareUltralightHandlerAndroid.js +23 -0
  47. package/dist/src/NfcTech/MifareUltralightHandlerAndroid.js.map +1 -0
  48. package/dist/src/NfcTech/NdefFormatableHandlerAndroid.js +16 -0
  49. package/dist/src/NfcTech/NdefFormatableHandlerAndroid.js.map +1 -0
  50. package/dist/src/NfcTech/NdefHandler.js +54 -0
  51. package/dist/src/NfcTech/NdefHandler.js.map +1 -0
  52. package/dist/src/NfcTech/NfcAHandler.js +16 -0
  53. package/dist/src/NfcTech/NfcAHandler.js.map +1 -0
  54. package/dist/src/NfcTech/NfcVHandler.js +33 -0
  55. package/dist/src/NfcTech/NfcVHandler.js.map +1 -0
  56. package/dist/src/index.js +53 -0
  57. package/dist/src/index.js.map +1 -0
  58. package/index.d.ts +76 -43
  59. package/ios/NfcManager.h +2 -10
  60. package/ios/NfcManager.mm +176 -434
  61. package/ios/RNNfcBridgeUtil.h +28 -0
  62. package/ios/RNNfcBridgeUtil.mm +52 -0
  63. package/ios/RNNfcManager+Felica.swift +61 -0
  64. package/ios/RNNfcManager+Iso15693.swift +895 -0
  65. package/ios/RNNfcManager+IsoDep.swift +145 -0
  66. package/ios/RNNfcManager+Mifare.swift +61 -0
  67. package/ios/RNNfcManager+Ndef.swift +120 -0
  68. package/ios/RNNfcManager.h +251 -0
  69. package/ios/RNNfcManager.swift +648 -0
  70. package/ios/RNNfcSessionDelegateProxy.swift +104 -0
  71. package/ios/RNNfcSwiftUtil.swift +34 -0
  72. package/ndef-lib/{constants.js → constants.ts} +2 -0
  73. package/ndef-lib/{index.js → index.ts} +23 -12
  74. package/ndef-lib/{ndef-text.js → ndef-text.ts} +7 -2
  75. package/ndef-lib/{ndef-uri.js → ndef-uri.ts} +8 -3
  76. package/ndef-lib/{ndef-wifi-simple.js → ndef-wifi-simple.ts} +34 -11
  77. package/ndef-lib/{ndef.js → ndef.ts} +49 -20
  78. package/ndef-lib/{stringifier.js → stringifier.ts} +27 -10
  79. package/ndef-lib/{util.js → util.ts} +13 -8
  80. package/package.json +21 -7
  81. package/react-native-nfc-manager.podspec +3 -2
  82. package/specs/NativeNfcManager.ts +17 -4
  83. package/src/NativeNfcManager.ts +84 -0
  84. package/src/{NfcError.js → NfcError.ts} +6 -17
  85. package/src/{NfcManager.js → NfcManager.ts} +49 -34
  86. package/src/{NfcManagerAndroid.js → NfcManagerAndroid.ts} +25 -8
  87. package/src/{NfcManagerIOS.js → NfcManagerIOS.ts} +31 -10
  88. package/src/NfcTech/{Iso15693HandlerIOS.js → Iso15693HandlerIOS.ts} +64 -36
  89. package/src/NfcTech/{IsoDepHandler.js → IsoDepHandler.ts} +8 -5
  90. package/src/NfcTech/{MifareClassicHandlerAndroid.js → MifareClassicHandlerAndroid.ts} +33 -24
  91. package/src/NfcTech/{MifareUltralightHandlerAndroid.js → MifareUltralightHandlerAndroid.ts} +14 -5
  92. package/src/NfcTech/{NdefFormatableHandlerAndroid.js → NdefFormatableHandlerAndroid.ts} +9 -2
  93. package/src/NfcTech/{NdefHandler.js → NdefHandler.ts} +19 -6
  94. package/src/NfcTech/{NfcAHandler.js → NfcAHandler.ts} +6 -3
  95. package/src/NfcTech/{NfcVHandler.js → NfcVHandler.ts} +8 -5
  96. package/src/__mocks__/{NativeNfcManager.js → NativeNfcManager.ts} +4 -1
  97. package/src/{index.js → index.ts} +1 -1
  98. package/android/src/main/java/community/revteltech/nfc/JsonConvert.java +0 -141
  99. package/android/src/main/java/community/revteltech/nfc/MifareUtil.java +0 -84
  100. package/ios/NfcManager+Felica.mm +0 -43
  101. package/ios/NfcManager+Iso15693.mm +0 -600
  102. package/ios/NfcManager+IsoDep.mm +0 -83
  103. package/ios/NfcManager+Mifare.mm +0 -43
  104. package/ios/Util.mm +0 -55
  105. package/specs/NativeNfcManager.js +0 -3
  106. package/specs/NativeNfcManager.js.map +0 -1
  107. package/src/NativeNfcManager.js +0 -37
@@ -1,9 +1,8 @@
1
1
  package community.revteltech.nfc;
2
2
 
3
- import android.annotation.SuppressLint;
3
+ import static community.revteltech.nfc.NfcErrorCodes.*;
4
+
4
5
  import android.app.Activity;
5
- import android.content.BroadcastReceiver;
6
- import android.content.Context;
7
6
  import android.content.Intent;
8
7
  import android.content.IntentFilter;
9
8
  import android.content.pm.PackageManager;
@@ -18,71 +17,34 @@ import com.facebook.react.modules.core.RCTNativeAppEventEmitter;
18
17
 
19
18
  import android.app.PendingIntent;
20
19
  import android.content.IntentFilter.MalformedMimeTypeException;
21
- import android.nfc.FormatException;
22
- import android.nfc.NdefMessage;
23
20
  import android.nfc.NfcAdapter;
24
21
  import android.nfc.Tag;
25
- import android.nfc.TagLostException;
26
- import android.nfc.tech.TagTechnology;
27
22
  import android.nfc.tech.Ndef;
28
- import android.nfc.tech.NfcA;
29
- import android.nfc.tech.NfcB;
30
- import android.nfc.tech.NfcF;
31
- import android.nfc.tech.NfcV;
32
- import android.nfc.tech.IsoDep;
33
- import android.nfc.tech.NdefFormatable;
34
- import android.nfc.tech.MifareClassic;
35
- import android.nfc.tech.MifareUltralight;
36
- import android.os.Parcelable;
37
23
  import android.os.Bundle;
38
-
39
- import org.json.JSONObject;
40
- import org.json.JSONException;
24
+ import android.os.Parcelable;
41
25
 
42
26
  import java.util.*;
43
27
 
44
- class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener, LifecycleEventListener {
28
+ class NfcManager extends NfcManagerIOSStubBase implements ActivityEventListener, LifecycleEventListener {
45
29
  private static final String LOG_TAG = "ReactNativeNfcManager";
46
30
  private final List<IntentFilter> intentFilters = new ArrayList<>();
47
31
  private final ArrayList<String[]> techLists = new ArrayList<>();
48
- private final ReactApplicationContext context;
49
32
  private Boolean isForegroundEnabled = false;
50
33
  private Boolean isResumed = false;
51
- private WriteNdefRequest writeNdefRequest = null;
34
+ private NdefHandler.WriteNdefRequest writeNdefRequest = null;
52
35
  private TagTechnologyRequest techRequest = null;
53
36
  private Tag tag = null;
54
37
  private WritableMap bgTag = null;
38
+ private Activity receiverActivity = null;
55
39
  // Use NFC reader mode instead of listening to a dispatch
56
40
  private Boolean isReaderModeEnabled = false;
57
41
  private int readerModeFlags = 0;
58
42
  private int readerModeDelay = 0;
59
- private static final String ERR_CANCEL = "cancelled";
60
- private static final String ERR_NOT_REGISTERED = "you should requestTagEvent first";
61
- private static final String ERR_MULTI_REQ = "You can only issue one request at a time";
62
- private static final String ERR_NO_TECH_REQ = "no tech request available";
63
- private static final String ERR_NO_REFERENCE = "no reference available";
64
- private static final String ERR_TRANSCEIVE_FAIL = "transceive fail";
65
- private static final String ERR_API_NOT_SUPPORT = "unsupported tag api";
66
- private static final String ERR_GET_ACTIVITY_FAIL = "fail to get current activity";
67
- private static final String ERR_NO_NFC_SUPPORT = "no nfc support";
68
-
69
- static class WriteNdefRequest {
70
- NdefMessage message;
71
- Callback callback;
72
- boolean format;
73
- boolean formatReadOnly;
74
-
75
- WriteNdefRequest(NdefMessage message, Callback callback, boolean format, boolean formatReadOnly) {
76
- this.message = message;
77
- this.callback = callback;
78
- this.format = format;
79
- this.formatReadOnly = formatReadOnly;
80
- }
81
- }
43
+ private final NfcAdapterStateChangedReceiver mReceiver =
44
+ new NfcAdapterStateChangedReceiver(LOG_TAG, this::emitAdapterStateChanged);
82
45
 
83
46
  public NfcManager(ReactApplicationContext reactContext) {
84
47
  super(reactContext);
85
- context = reactContext;
86
48
  reactContext.addActivityEventListener(this);
87
49
  reactContext.addLifecycleEventListener(this);
88
50
  Log.d(LOG_TAG, "NfcManager created");
@@ -98,31 +60,23 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
98
60
  public Map<String, Object> getConstants() {
99
61
  final Map<String, Object> constants = new HashMap<>();
100
62
 
101
- constants.put("MIFARE_BLOCK_SIZE", MifareClassic.BLOCK_SIZE);
102
- constants.put("MIFARE_ULTRALIGHT_PAGE_SIZE", MifareUltralight.PAGE_SIZE);
103
- constants.put("MIFARE_ULTRALIGHT_TYPE", MifareUltralight.TYPE_ULTRALIGHT);
104
- constants.put("MIFARE_ULTRALIGHT_TYPE_C", MifareUltralight.TYPE_ULTRALIGHT_C);
105
- constants.put("MIFARE_ULTRALIGHT_TYPE_UNKNOWN", MifareUltralight.TYPE_UNKNOWN);
63
+ MifareClassicHandler.putConstants(constants);
64
+ MifareUltralightHandler.putConstants(constants);
106
65
 
107
66
  return constants;
108
67
  }
109
68
 
110
- private boolean hasPendingRequest() {
111
- return writeNdefRequest != null || techRequest != null;
112
- }
113
-
114
69
  @ReactMethod
115
70
  public void cancelTechnologyRequest(Callback callback) {
116
71
  synchronized(this) {
117
- if (techRequest != null) {
118
- techRequest.close();
72
+ TagTechnologyRequest request = detachTechnologyRequest();
73
+ if (request != null) {
74
+ request.close();
119
75
  try {
120
- techRequest.invokePendingCallbackWithError(ERR_CANCEL);
76
+ request.invokePendingCallbackWithError(ERR_CANCEL);
121
77
  } catch (RuntimeException ex) {
122
- // the pending callback might already been invoked when there is an ongoing
123
- // connected tag, bypass this case explicitly
78
+ Log.w(LOG_TAG, "fail to complete cancelled technology request", ex);
124
79
  }
125
- techRequest = null;
126
80
  }
127
81
  callback.invoke();
128
82
  }
@@ -147,9 +101,14 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
147
101
  @ReactMethod
148
102
  public void closeTechnology(Callback callback) {
149
103
  synchronized(this) {
150
- if (techRequest != null) {
151
- techRequest.close();
152
- techRequest = null;
104
+ TagTechnologyRequest request = detachTechnologyRequest();
105
+ if (request != null) {
106
+ request.close();
107
+ try {
108
+ request.invokePendingCallbackWithError(ERR_CANCEL);
109
+ } catch (RuntimeException ex) {
110
+ Log.w(LOG_TAG, "fail to complete closed technology request", ex);
111
+ }
153
112
  }
154
113
  callback.invoke();
155
114
  }
@@ -161,11 +120,10 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
161
120
  if (techRequest != null) {
162
121
  Tag tag = techRequest.getTagHandle();
163
122
  if (tag != null) {
164
- WritableMap parsed = tag2React(tag);
123
+ WritableMap parsed = Util.tagToReact(tag);
165
124
  if (Arrays.asList(tag.getTechList()).contains(Ndef.class.getName())) {
166
125
  try {
167
- Ndef ndef = Ndef.get(tag);
168
- parsed = ndef2React(ndef, new NdefMessage[]{ndef.getCachedNdefMessage()});
126
+ parsed = NdefHandler.ndefToReact(tag);
169
127
  } catch (Exception ex) {
170
128
  Log.d(LOG_TAG, ex.toString());
171
129
  }
@@ -183,904 +141,329 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
183
141
  @ReactMethod
184
142
  public void getCachedNdefMessage(Callback callback) {
185
143
  synchronized(this) {
186
- if (techRequest != null) {
187
- try {
188
- Ndef ndef = Ndef.get(techRequest.getTagHandle());
189
- WritableMap parsed = ndef2React(ndef, new NdefMessage[] { ndef.getCachedNdefMessage() });
190
- callback.invoke(null, parsed);
191
- } catch (Exception ex) {
192
- Log.d(LOG_TAG, ex.toString());
193
- callback.invoke(ex.toString());
194
- }
195
- } else {
196
- callback.invoke(ERR_NO_TECH_REQ);
197
- }
144
+ NdefHandler.getCachedNdefMessage(techRequest, callback);
198
145
  }
199
146
  }
200
147
 
201
148
  @ReactMethod
202
149
  public void getNdefMessage(Callback callback) {
203
150
  synchronized(this) {
204
- if (techRequest != null) {
205
- try {
206
- Ndef ndef = Ndef.get(techRequest.getTagHandle());
207
- WritableMap parsed = ndef2React(null, new NdefMessage[] { ndef.getNdefMessage() });
208
- callback.invoke(null, parsed);
209
- } catch (Exception ex) {
210
- Log.d(LOG_TAG, ex.toString());
211
- callback.invoke(ex.toString());
212
- }
213
- } else {
214
- callback.invoke(ERR_NO_TECH_REQ);
215
- }
151
+ NdefHandler.getNdefMessage(techRequest, callback);
216
152
  }
217
153
  }
218
154
 
219
155
  @ReactMethod
220
156
  public void queryNdefStatus(Callback callback) {
221
157
  synchronized(this) {
222
- if (techRequest != null) {
223
- WritableMap writableMap = Arguments.createMap();
224
- try {
225
- Ndef ndef = Ndef.get(techRequest.getTagHandle());
226
- int maxSize = ndef.getMaxSize();
227
- boolean isWritable = ndef.isWritable();
228
- boolean canMakeReadOnly = ndef.canMakeReadOnly();
229
- writableMap.putInt("maxSize", maxSize);
230
- writableMap.putBoolean("isWritable", isWritable);
231
- writableMap.putBoolean("canMakeReadOnly", canMakeReadOnly);
232
- callback.invoke(null, writableMap);
233
- } catch (Exception ex) {
234
- Log.d(LOG_TAG, ex.toString());
235
- callback.invoke(ex.toString());
236
- }
237
- } else {
238
- callback.invoke(ERR_NO_TECH_REQ);
239
- }
158
+ NdefHandler.queryNdefStatus(techRequest, callback);
240
159
  }
241
160
  }
242
161
 
243
162
  @ReactMethod
244
163
  public void writeNdefMessage(ReadableArray rnArray, ReadableMap options, Callback callback) {
245
164
  synchronized(this) {
246
- boolean reconnectAfterWrite = options.getBoolean("reconnectAfterWrite");
247
-
248
- if (techRequest != null) {
249
- try {
250
- Ndef ndef = (Ndef)techRequest.getTechHandle();
251
- if (ndef == null) {
252
- callback.invoke(ERR_API_NOT_SUPPORT);
253
- } else {
254
- byte[] bytes = rnArrayToBytes(rnArray);
255
- ndef.writeNdefMessage(new NdefMessage(bytes));
256
- if (reconnectAfterWrite) {
257
- ndef.close();
258
- //reconnection is needed in order to be able to read the written ndef
259
- ndef.connect();
260
- }
261
- callback.invoke();
262
- }
263
- } catch (Exception ex) {
264
- Log.d(LOG_TAG, ex.toString());
265
- callback.invoke(ex.toString());
266
- }
267
- } else {
268
- callback.invoke(ERR_NO_TECH_REQ);
269
- }
165
+ NdefHandler.writeNdefMessage(
166
+ techRequest,
167
+ rnArray,
168
+ options,
169
+ callback
170
+ );
270
171
  }
271
172
  }
272
173
 
273
174
  @ReactMethod
274
175
  public void formatNdef(ReadableArray rnArray, ReadableMap options, Callback callback) {
275
- boolean readOnly = options.getBoolean("readOnly");
276
-
277
176
  synchronized(this) {
278
- if (techRequest != null) {
279
- try {
280
- NdefFormatable ndef = (NdefFormatable)techRequest.getTechHandle();
281
- if (ndef == null) {
282
- callback.invoke(ERR_API_NOT_SUPPORT);
283
- } else {
284
- byte[] bytes = rnArrayToBytes(rnArray);
285
- NdefMessage msg = new NdefMessage(bytes);
286
- if (readOnly) {
287
- ndef.formatReadOnly(msg);
288
- } else {
289
- ndef.format(msg);
290
- }
291
- callback.invoke();
292
- }
293
- } catch (Exception ex) {
294
- Log.d(LOG_TAG, ex.toString());
295
- callback.invoke(ex.toString());
296
- }
297
- } else {
298
- callback.invoke(ERR_NO_TECH_REQ);
299
- }
300
- }
301
- }
302
-
303
- private void mifareClassicAuthenticate(char type, int sector, ReadableArray key, Callback callback) {
304
- if (techRequest != null) {
305
- try {
306
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
307
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
308
- // Not a mifare card, fail
309
- callback.invoke("mifareClassicAuthenticate fail: TYPE_UNKNOWN");
310
- return;
311
- } else if (sector >= mifareTag.getSectorCount()) {
312
- // Check if in range
313
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicAuthenticate fail: invalid sector %d (max %d)", sector, mifareTag.getSectorCount());
314
- callback.invoke(msg);
315
- return;
316
- } else if (key.size() != 6) {
317
- // Invalid key length
318
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicAuthenticate fail: invalid key (needs length 6 but has %d characters)", key.size());
319
- callback.invoke(msg);
320
- return;
321
- }
322
-
323
- boolean result;
324
- if (type == 'A') {
325
- result = mifareTag.authenticateSectorWithKeyA(sector, rnArrayToBytes(key));
326
- } else {
327
- result = mifareTag.authenticateSectorWithKeyB(sector, rnArrayToBytes(key));
328
- }
329
-
330
- if (!result) {
331
- callback.invoke("mifareClassicAuthenticate fail: AUTH_FAIL");
332
- return;
333
- }
334
-
335
- callback.invoke(null, true);
336
- } catch (TagLostException ex) {
337
- callback.invoke("mifareClassicAuthenticate fail: TAG_LOST");
338
- } catch (Exception ex) {
339
- callback.invoke("mifareClassicAuthenticate fail: " + ex);
340
- }
341
- } else {
342
- callback.invoke(ERR_NO_TECH_REQ);
177
+ NdefHandler.formatNdef(
178
+ techRequest,
179
+ rnArray,
180
+ options,
181
+ callback
182
+ );
343
183
  }
344
184
  }
345
185
 
346
186
  @ReactMethod
347
187
  public void mifareClassicAuthenticateA(double sector, ReadableArray key, Callback callback) {
348
188
  synchronized(this) {
349
- mifareClassicAuthenticate('A', (int)sector, key, callback);
189
+ MifareClassicHandler.authenticate(techRequest, 'A', (int)sector, key, callback);
350
190
  }
351
191
  }
352
192
 
353
193
  @ReactMethod
354
194
  public void mifareClassicAuthenticateB(double sector, ReadableArray key, Callback callback) {
355
195
  synchronized(this) {
356
- mifareClassicAuthenticate('B', (int)sector, key, callback);
196
+ MifareClassicHandler.authenticate(techRequest, 'B', (int)sector, key, callback);
357
197
  }
358
198
  }
359
199
 
360
200
  @ReactMethod
361
201
  public void mifareClassicGetBlockCountInSector(double _sectorIndex, Callback callback) {
362
- int sectorIndex = (int)_sectorIndex;
363
202
  synchronized(this) {
364
- if (techRequest != null) {
365
- try {
366
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
367
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
368
- // Not a mifare card, fail
369
- callback.invoke("mifareClassicGetBlockCountInSector fail: TYPE_UNKNOWN");
370
- return;
371
- } else if (sectorIndex >= mifareTag.getSectorCount()) {
372
- // Check if in range
373
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicGetBlockCountInSector fail: invalid sector %d (max %d)", sectorIndex, mifareTag.getSectorCount());
374
- callback.invoke(msg);
375
- return;
376
- }
377
-
378
- callback.invoke(null, mifareTag.getBlockCountInSector(sectorIndex));
379
- } catch (Exception ex) {
380
- callback.invoke("mifareClassicGetBlockCountInSector fail: " + ex);
381
- }
382
- } else {
383
- callback.invoke(ERR_NO_TECH_REQ);
384
- }
203
+ MifareClassicHandler.getBlockCountInSector(
204
+ techRequest,
205
+ (int)_sectorIndex,
206
+ callback
207
+ );
385
208
  }
386
209
  }
387
210
 
388
211
  @ReactMethod
389
212
  public void mifareClassicGetSectorCount(Callback callback) {
390
213
  synchronized(this) {
391
- if (techRequest != null) {
392
- try {
393
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
394
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
395
- // Not a mifare card, fail
396
- callback.invoke("mifareClassicGetSectorCount fail: TYPE_UNKNOWN");
397
- return;
398
- }
399
-
400
- callback.invoke(null, mifareTag.getSectorCount());
401
- } catch (Exception ex) {
402
- callback.invoke("mifareClassicGetSectorCount fail: " + ex);
403
- }
404
- } else {
405
- callback.invoke(ERR_NO_TECH_REQ);
406
- }
214
+ MifareClassicHandler.getSectorCount(techRequest, callback);
407
215
  }
408
216
  }
409
217
 
410
218
  @ReactMethod
411
219
  public void mifareClassicSectorToBlock(double _sectorIndex, Callback callback) {
412
- int sectorIndex = (int)_sectorIndex;
413
220
  synchronized(this) {
414
- if (techRequest != null) {
415
- try {
416
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
417
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
418
- // Not a mifare card, fail
419
- callback.invoke("mifareClassicSectorToBlock fail: TYPE_UNKNOWN");
420
- return;
421
- } else if (sectorIndex >= mifareTag.getSectorCount()) {
422
- // Check if in range
423
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicSectorToBlock fail: invalid sector %d (max %d)", sectorIndex, mifareTag.getSectorCount());
424
- callback.invoke(msg);
425
- return;
426
- }
427
-
428
- callback.invoke(null, mifareTag.sectorToBlock(sectorIndex));
429
- } catch (Exception ex) {
430
- callback.invoke("mifareClassicSectorToBlock fail: " + ex);
431
- }
432
- } else {
433
- callback.invoke(ERR_NO_TECH_REQ);
434
- }
221
+ MifareClassicHandler.sectorToBlock(
222
+ techRequest,
223
+ (int)_sectorIndex,
224
+ callback
225
+ );
435
226
  }
436
227
  }
437
228
 
438
229
  @ReactMethod
439
230
  public void mifareClassicReadBlock(double _blockIndex, Callback callback) {
440
- int blockIndex = (int)_blockIndex;
441
231
  synchronized(this) {
442
- if (techRequest != null) {
443
- try {
444
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
445
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
446
- // Not a mifare card, fail
447
- callback.invoke("mifareClassicReadBlock fail: TYPE_UNKNOWN");
448
- return;
449
- } else if (blockIndex >= mifareTag.getBlockCount()) {
450
- // Check if in range
451
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicReadBlock fail: invalid block %d (max %d)", blockIndex, mifareTag.getBlockCount());
452
- callback.invoke(msg);
453
- return;
454
- }
455
-
456
- byte[] buffer = mifareTag.readBlock(blockIndex);
457
-
458
- WritableArray result = bytesToRnArray(buffer);
459
- callback.invoke(null, result);
460
- } catch (TagLostException ex) {
461
- callback.invoke("mifareClassicReadBlock fail: TAG_LOST");
462
- } catch (Exception ex) {
463
- callback.invoke("mifareClassicReadBlock fail: " + ex);
464
- }
465
- } else {
466
- callback.invoke(ERR_NO_TECH_REQ);
467
- }
232
+ MifareClassicHandler.readBlock(
233
+ techRequest,
234
+ (int)_blockIndex,
235
+ callback
236
+ );
468
237
  }
469
238
  }
470
239
 
471
240
  @ReactMethod
472
241
  public void mifareClassicReadSector(double _sectorIndex, Callback callback) {
473
- int sectorIndex = (int)_sectorIndex;
474
242
  synchronized(this) {
475
- if (techRequest != null) {
476
- try {
477
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
478
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
479
- // Not a mifare card, fail
480
- callback.invoke("mifareClassicReadSector fail: TYPE_UNKNOWN");
481
- return;
482
- } else if (sectorIndex >= mifareTag.getSectorCount()) {
483
- // Check if in range
484
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicReadSector fail: invalid sector %d (max %d)", sectorIndex, mifareTag.getSectorCount());
485
- callback.invoke(msg);
486
- return;
487
- }
488
-
489
- WritableArray result = Arguments.createArray();
490
- int blocks = mifareTag.getBlockCountInSector(sectorIndex);
491
- byte[] buffer;
492
- for (int i = 0; i < blocks; i++) {
493
- buffer = mifareTag.readBlock(mifareTag.sectorToBlock(sectorIndex)+i);
494
- appendBytesToRnArray(result, buffer);
495
- }
496
-
497
- callback.invoke(null, result);
498
- } catch (TagLostException ex) {
499
- callback.invoke("mifareClassicReadSector fail: TAG_LOST");
500
- } catch (Exception ex) {
501
- callback.invoke("mifareClassicReadSector fail: " + ex);
502
- }
503
- } else {
504
- callback.invoke(ERR_NO_TECH_REQ);
505
- }
243
+ MifareClassicHandler.readSector(
244
+ techRequest,
245
+ (int)_sectorIndex,
246
+ callback
247
+ );
506
248
  }
507
249
  }
508
250
 
509
251
  @ReactMethod
510
252
  public void mifareClassicWriteBlock(double _blockIndex, ReadableArray block, Callback callback) {
511
- int blockIndex = (int)_blockIndex;
512
253
  synchronized(this) {
513
- if (techRequest != null) {
514
- try {
515
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
516
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
517
- // Not a mifare card, fail
518
- callback.invoke("mifareClassicWriteBlock fail: TYPE_UNKNOWN");
519
- return;
520
- } else if (blockIndex >= mifareTag.getBlockCount()) {
521
- // Check if in range
522
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicWriteBlock fail: invalid block %d (max %d)", blockIndex, mifareTag.getBlockCount());
523
- callback.invoke(msg);
524
- return;
525
- } else if (block.size() != MifareClassic.BLOCK_SIZE) {
526
- // Wrong block count
527
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicWriteBlock fail: invalid block size %d (should be %d)", block.size(), MifareClassic.BLOCK_SIZE);
528
- callback.invoke(msg);
529
- return;
530
- }
531
-
532
- byte[] buffer = rnArrayToBytes(block);
533
- mifareTag.writeBlock(blockIndex, buffer);
534
-
535
- callback.invoke(null, true);
536
- } catch (TagLostException ex) {
537
- callback.invoke("mifareClassicWriteBlock fail: TAG_LOST");
538
- } catch (Exception ex) {
539
- callback.invoke("mifareClassicWriteBlock fail: " + ex);
540
- }
541
- } else {
542
- callback.invoke(ERR_NO_TECH_REQ);
543
- }
254
+ MifareClassicHandler.writeBlock(
255
+ techRequest,
256
+ (int)_blockIndex,
257
+ block,
258
+ callback
259
+ );
544
260
  }
545
261
  }
546
262
 
547
263
  @ReactMethod
548
264
  public void mifareClassicIncrementBlock(double _blockIndex, double _value, Callback callback) {
549
- int blockIndex = (int)_blockIndex;
550
- int value = (int)_value;
551
265
  synchronized(this) {
552
- if (techRequest != null) {
553
- try {
554
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
555
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
556
- // Not a mifare card, fail
557
- callback.invoke("mifareClassicIncrementBlock fail: TYPE_UNKNOWN");
558
- return;
559
- } else if (blockIndex >= mifareTag.getBlockCount()) {
560
- // Check if in range
561
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicIncrementBlock fail: invalid block %d (max %d)", blockIndex, mifareTag.getBlockCount());
562
- callback.invoke(msg);
563
- return;
564
- }
565
-
566
- mifareTag.increment(blockIndex, value);
567
-
568
- callback.invoke(null, true);
569
- } catch (TagLostException ex) {
570
- callback.invoke("mifareClassicIncrementBlock fail: TAG_LOST");
571
- } catch (Exception ex) {
572
- callback.invoke("mifareClassicIncrementBlock fail: " + ex);
573
- }
574
- } else {
575
- callback.invoke(ERR_NO_TECH_REQ);
576
- }
266
+ MifareClassicHandler.incrementBlock(
267
+ techRequest,
268
+ (int)_blockIndex,
269
+ (int)_value,
270
+ callback
271
+ );
577
272
  }
578
273
  }
579
274
 
580
275
  @ReactMethod
581
276
  public void mifareClassicDecrementBlock(double _blockIndex, double _value, Callback callback) {
582
- int blockIndex = (int)_blockIndex;
583
- int value = (int)_value;
584
277
  synchronized(this) {
585
- if (techRequest != null) {
586
- try {
587
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
588
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
589
- // Not a mifare card, fail
590
- callback.invoke("mifareClassicDecrementBlock fail: TYPE_UNKNOWN");
591
- return;
592
- } else if (blockIndex >= mifareTag.getBlockCount()) {
593
- // Check if in range
594
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicDecrementBlock fail: invalid block %d (max %d)", blockIndex, mifareTag.getBlockCount());
595
- callback.invoke(msg);
596
- return;
597
- }
598
-
599
- mifareTag.decrement(blockIndex, value);
600
-
601
- callback.invoke(null, true);
602
- } catch (TagLostException ex) {
603
- callback.invoke("mifareClassicDecrementBlock fail: TAG_LOST");
604
- } catch (Exception ex) {
605
- callback.invoke("mifareClassicDecrementBlock fail: " + ex);
606
- }
607
- } else {
608
- callback.invoke(ERR_NO_TECH_REQ);
609
- }
278
+ MifareClassicHandler.decrementBlock(
279
+ techRequest,
280
+ (int)_blockIndex,
281
+ (int)_value,
282
+ callback
283
+ );
610
284
  }
611
285
  }
612
286
 
613
287
  @ReactMethod
614
288
  public void mifareClassicTransferBlock(double _blockIndex, Callback callback) {
615
- int blockIndex = (int)_blockIndex;
616
289
  synchronized(this) {
617
- if (techRequest != null) {
618
- try {
619
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
620
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
621
- // Not a mifare card, fail
622
- callback.invoke("mifareClassicTransferBlock fail: TYPE_UNKNOWN");
623
- return;
624
- } else if (blockIndex >= mifareTag.getBlockCount()) {
625
- // Check if in range
626
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicTransferBlock fail: invalid block %d (max %d)", blockIndex, mifareTag.getBlockCount());
627
- callback.invoke(msg);
628
- return;
629
- }
630
-
631
- mifareTag.transfer(blockIndex);
632
-
633
- callback.invoke(null, true);
634
- } catch (TagLostException ex) {
635
- callback.invoke("mifareClassicTransferBlock fail: TAG_LOST");
636
- } catch (Exception ex) {
637
- callback.invoke("mifareClassicTransferBlock fail: " + ex);
638
- }
639
- } else {
640
- callback.invoke(ERR_NO_TECH_REQ);
641
- }
290
+ MifareClassicHandler.transferBlock(
291
+ techRequest,
292
+ (int)_blockIndex,
293
+ callback
294
+ );
642
295
  }
643
296
  }
644
297
 
645
298
  @ReactMethod
646
299
  public void mifareUltralightReadPages(double pageOffset, Callback callback) {
647
300
  synchronized(this) {
648
- if (techRequest != null) {
649
- try {
650
- MifareUltralight techHandle = (MifareUltralight)techRequest.getTechHandle();
651
- byte[] resultBytes = techHandle.readPages((int)pageOffset);
652
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
653
- callback.invoke(null, resultRnArray);
654
- } catch (TagLostException ex) {
655
- callback.invoke("mifareUltralight fail: TAG_LOST");
656
- } catch (Exception ex) {
657
- callback.invoke("mifareUltralight fail: " + ex);
658
- }
659
- } else {
660
- callback.invoke(ERR_NO_TECH_REQ);
661
- }
301
+ MifareUltralightHandler.readPages(
302
+ techRequest,
303
+ (int)pageOffset,
304
+ callback
305
+ );
662
306
  }
663
307
  }
664
308
 
665
309
  @ReactMethod
666
310
  public void mifareUltralightWritePage(double pageOffset, ReadableArray rnArray, Callback callback) {
667
311
  synchronized(this) {
668
- if (techRequest != null) {
669
- try {
670
- byte[] bytes = rnArrayToBytes(rnArray);
671
- MifareUltralight techHandle = (MifareUltralight)techRequest.getTechHandle();
672
- techHandle.writePage((int)pageOffset, bytes);
673
- callback.invoke();
674
- } catch (TagLostException ex) {
675
- callback.invoke("mifareUltralight fail: TAG_LOST");
676
- } catch (Exception ex) {
677
- callback.invoke("mifareUltralight fail: " + ex);
678
- }
679
- } else {
680
- callback.invoke(ERR_NO_TECH_REQ);
681
- }
312
+ MifareUltralightHandler.writePage(
313
+ techRequest,
314
+ (int)pageOffset,
315
+ rnArray,
316
+ callback
317
+ );
682
318
  }
683
319
  }
684
320
 
685
321
  @ReactMethod
686
322
  public void makeReadOnly(Callback callback) {
687
323
  synchronized(this) {
688
- if (techRequest != null) {
689
- try {
690
- Ndef ndef = (Ndef)techRequest.getTechHandle();
691
- boolean result = ndef.makeReadOnly();
692
- callback.invoke(null, result);
693
- } catch (Exception ex) {
694
- Log.d(LOG_TAG, ex.toString());
695
- callback.invoke(ex.toString());
696
- }
697
- } else {
698
- callback.invoke(ERR_NO_TECH_REQ);
699
- }
324
+ NdefHandler.makeReadOnly(techRequest, callback);
700
325
  }
701
326
  }
702
327
 
703
- @Override
704
- public void setAlertMessage(String message, Callback callback) {
705
-
706
- }
707
-
708
- @Override
709
- public void isSessionAvailable(Callback callback) {
710
-
711
- }
712
-
713
- @Override
714
- public void isTagSessionAvailable(Callback callback) {
715
-
716
- }
717
-
718
- @Override
719
- public void sendMifareCommand(ReadableArray bytes, Callback callback) {
720
-
721
- }
722
-
723
- @Override
724
- public void sendCommandAPDU(ReadableMap payload, Callback callback) {
725
-
726
- }
727
-
728
- @Override
729
- public void sendCommandAPDUBytes(ReadableArray bytes, Callback callback) {
730
-
731
- }
732
-
733
- @Override
734
- public void sendFelicaCommand(ReadableArray bytes, Callback callback) {
735
-
736
- }
737
-
738
328
  @ReactMethod
739
329
  public void setTimeout(double timeout, Callback callback) {
740
330
  synchronized (this) {
741
- if (techRequest != null) {
742
- try {
743
- String tech = techRequest.getTechType();
744
- TagTechnology baseTechHandle = techRequest.getTechHandle();
745
- // TagTechnology is the base class for each tech (ex, NfcA, NfcB, IsoDep ...)
746
- // but it doesn't provide transceive in its interface, so we need to explicitly cast it
747
- switch (tech) {
748
- case "NfcA": {
749
- NfcA techHandle = (NfcA) baseTechHandle;
750
- techHandle.setTimeout((int)timeout);
751
- callback.invoke();
752
- return;
753
- }
754
- case "NfcF": {
755
- NfcF techHandle = (NfcF) baseTechHandle;
756
- techHandle.setTimeout((int)timeout);
757
- callback.invoke();
758
- return;
759
- }
760
- case "IsoDep": {
761
- IsoDep techHandle = (IsoDep) baseTechHandle;
762
- techHandle.setTimeout((int)timeout);
763
- callback.invoke();
764
- return;
765
- }
766
- case "MifareClassic": {
767
- MifareClassic techHandle = (MifareClassic) baseTechHandle;
768
- techHandle.setTimeout((int)timeout);
769
- callback.invoke();
770
- return;
771
- }
772
- case "MifareUltralight": {
773
- MifareUltralight techHandle = (MifareUltralight) baseTechHandle;
774
- techHandle.setTimeout((int)timeout);
775
- callback.invoke();
776
- return;
777
- }
778
- }
779
- Log.d(LOG_TAG, "setTimeout not supported");
780
- callback.invoke(ERR_API_NOT_SUPPORT);
781
- } catch (Exception ex) {
782
- Log.d(LOG_TAG, ex.toString());
783
- callback.invoke(ex.toString());
784
- }
785
- } else {
786
- callback.invoke(ERR_NO_TECH_REQ);
787
- }
331
+ NfcTechIoRouter.setTimeout(
332
+ techRequest,
333
+ (int)timeout,
334
+ callback
335
+ );
788
336
  }
789
337
  }
790
338
 
791
339
  @ReactMethod
792
340
  public void getTimeout(Callback callback) {
793
341
  synchronized (this) {
794
- if (techRequest != null) {
795
- try {
796
- String tech = techRequest.getTechType();
797
- TagTechnology baseTechHandle = techRequest.getTechHandle();
798
- // TagTechnology is the base class for each tech (ex, NfcA, NfcB, IsoDep ...)
799
- // but it doesn't provide transceive in its interface, so we need to explicitly cast it
800
- switch (tech) {
801
- case "NfcA": {
802
- NfcA techHandle = (NfcA) baseTechHandle;
803
- int timeout = techHandle.getTimeout();
804
- callback.invoke(null, timeout);
805
- return;
806
- }
807
- case "NfcF": {
808
- NfcF techHandle = (NfcF) baseTechHandle;
809
- int timeout = techHandle.getTimeout();
810
- callback.invoke(null, timeout);
811
- return;
812
- }
813
- case "IsoDep": {
814
- IsoDep techHandle = (IsoDep) baseTechHandle;
815
- int timeout = techHandle.getTimeout();
816
- callback.invoke(null, timeout);
817
- return;
818
- }
819
- case "MifareClassic": {
820
- MifareClassic techHandle = (MifareClassic) baseTechHandle;
821
- int timeout = techHandle.getTimeout();
822
- callback.invoke(null, timeout);
823
- return;
824
- }
825
- case "MifareUltralight": {
826
- MifareUltralight techHandle = (MifareUltralight) baseTechHandle;
827
- int timeout = techHandle.getTimeout();
828
- callback.invoke(null, timeout);
829
- return;
830
- }
831
- }
832
- Log.d(LOG_TAG, "getTimeout not supported");
833
- callback.invoke(ERR_API_NOT_SUPPORT);
834
- } catch (Exception ex) {
835
- Log.d(LOG_TAG, ex.toString());
836
- callback.invoke(ex.toString());
837
- }
838
- } else {
839
- callback.invoke(ERR_NO_TECH_REQ);
840
- }
342
+ NfcTechIoRouter.getTimeout(techRequest, callback);
841
343
  }
842
344
  }
843
345
 
844
346
  @ReactMethod
845
347
  public void connect(ReadableArray techs, Callback callback){
846
348
  synchronized(this) {
349
+ if (hasPendingRequest()) {
350
+ callback.invoke(ERR_MULTI_REQ);
351
+ return;
352
+ }
353
+
354
+ TagTechnologyRequest request = new TagTechnologyRequest(techs.toArrayList(), null);
847
355
  try {
848
- techRequest = new TagTechnologyRequest(techs.toArrayList(), null);
849
- techRequest.connect(this.tag);
850
- callback.invoke(null, null);
356
+ if (!request.connect(this.tag)) {
357
+ request.close();
358
+ callback.invoke(this.tag == null ? ERR_NO_REFERENCE : ERR_API_NOT_SUPPORT);
359
+ return;
360
+ }
361
+ techRequest = request;
851
362
  } catch (Exception ex) {
852
363
  callback.invoke(ex.toString());
364
+ return;
853
365
  }
366
+ callback.invoke(null, null);
854
367
  }
855
368
  }
856
369
 
857
370
  @ReactMethod
858
371
  public void close(Callback callback){
859
372
  synchronized(this) {
373
+ TagTechnologyRequest request = detachTechnologyRequest();
374
+ if (request == null) {
375
+ callback.invoke(ERR_NO_TECH_REQ);
376
+ return;
377
+ }
378
+
379
+ request.close();
860
380
  try {
861
- techRequest.close();
862
- callback.invoke(null, null);
863
- } catch (Exception ex) {
864
- callback.invoke(ex.toString());
381
+ request.invokePendingCallbackWithError(ERR_CANCEL);
382
+ } catch (RuntimeException ex) {
383
+ Log.w(LOG_TAG, "fail to complete closed technology request", ex);
865
384
  }
385
+ callback.invoke(null, null);
866
386
  }
867
387
  }
868
388
 
869
389
  @ReactMethod
870
390
  public void transceive(ReadableArray rnArray, Callback callback) {
871
391
  synchronized(this) {
872
- if (techRequest != null) {
873
- try {
874
- String tech = techRequest.getTechType();
875
- byte[] bytes = rnArrayToBytes(rnArray);
876
-
877
- TagTechnology baseTechHandle = techRequest.getTechHandle();
878
- // TagTechnology is the base class for each tech (ex, NfcA, NfcB, IsoDep ...)
879
- // but it doesn't provide transceive in its interface, so we need to explicitly cast it
880
- switch (tech) {
881
- case "NfcA": {
882
- NfcA techHandle = (NfcA) baseTechHandle;
883
- byte[] resultBytes = techHandle.transceive(bytes);
884
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
885
- callback.invoke(null, resultRnArray);
886
- return;
887
- }
888
- case "NfcB": {
889
- NfcB techHandle = (NfcB) baseTechHandle;
890
- byte[] resultBytes = techHandle.transceive(bytes);
891
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
892
- callback.invoke(null, resultRnArray);
893
- return;
894
- }
895
- case "NfcF": {
896
- NfcF techHandle = (NfcF) baseTechHandle;
897
- byte[] resultBytes = techHandle.transceive(bytes);
898
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
899
- callback.invoke(null, resultRnArray);
900
- return;
901
- }
902
- case "NfcV": {
903
- NfcV techHandle = (NfcV) baseTechHandle;
904
- byte[] resultBytes = techHandle.transceive(bytes);
905
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
906
- callback.invoke(null, resultRnArray);
907
- return;
908
- }
909
- case "IsoDep": {
910
- IsoDep techHandle = (IsoDep) baseTechHandle;
911
- byte[] resultBytes = techHandle.transceive(bytes);
912
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
913
- callback.invoke(null, resultRnArray);
914
- return;
915
- }
916
- case "MifareClassic": {
917
- MifareClassic techHandle = (MifareClassic) baseTechHandle;
918
- byte[] resultBytes = techHandle.transceive(bytes);
919
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
920
- callback.invoke(null, resultRnArray);
921
- return;
922
- }
923
- case "MifareUltralight": {
924
- MifareUltralight techHandle = (MifareUltralight) baseTechHandle;
925
- byte[] resultBytes = techHandle.transceive(bytes);
926
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
927
- callback.invoke(null, resultRnArray);
928
- return;
929
- }
930
- }
931
- Log.d(LOG_TAG, "transceive not supported");
932
- callback.invoke(ERR_API_NOT_SUPPORT);
933
- } catch (Exception ex) {
934
- Log.d(LOG_TAG, "transceive fail: " + ex);
935
- callback.invoke(ERR_TRANSCEIVE_FAIL);
936
- }
937
- } else {
938
- callback.invoke(ERR_NO_TECH_REQ);
939
- }
392
+ NfcTechIoRouter.transceive(
393
+ techRequest,
394
+ rnArray,
395
+ callback
396
+ );
940
397
  }
941
398
  }
942
399
 
943
400
  @ReactMethod
944
401
  public void getMaxTransceiveLength(Callback callback) {
945
402
  synchronized(this) {
946
- if (techRequest != null) {
947
- try {
948
- String tech = techRequest.getTechType();
949
-
950
- TagTechnology baseTechHandle = techRequest.getTechHandle();
951
- // TagTechnology is the base class for each tech (ex, NfcA, NfcB, IsoDep ...)
952
- // but it doesn't provide transceive in its interface, so we need to explicitly cast it
953
- switch (tech) {
954
- case "NfcA": {
955
- NfcA techHandle = (NfcA) baseTechHandle;
956
- int max = techHandle.getMaxTransceiveLength();
957
- callback.invoke(null, max);
958
- return;
959
- }
960
- case "NfcB": {
961
- NfcB techHandle = (NfcB) baseTechHandle;
962
- int max = techHandle.getMaxTransceiveLength();
963
- callback.invoke(null, max);
964
- return;
965
- }
966
- case "NfcF": {
967
- NfcF techHandle = (NfcF) baseTechHandle;
968
- int max = techHandle.getMaxTransceiveLength();
969
- callback.invoke(null, max);
970
- return;
971
- }
972
- case "NfcV": {
973
- NfcV techHandle = (NfcV) baseTechHandle;
974
- int max = techHandle.getMaxTransceiveLength();
975
- callback.invoke(null, max);
976
- return;
977
- }
978
- case "IsoDep": {
979
- IsoDep techHandle = (IsoDep) baseTechHandle;
980
- int max = techHandle.getMaxTransceiveLength();
981
- callback.invoke(null, max);
982
- return;
983
- }
984
- case "MifareUltralight": {
985
- MifareUltralight techHandle = (MifareUltralight) baseTechHandle;
986
- int max = techHandle.getMaxTransceiveLength();
987
- callback.invoke(null, max);
988
- return;
989
- }
990
- }
991
- Log.d(LOG_TAG, "getMaxTransceiveLength not supported");
992
- callback.invoke(ERR_API_NOT_SUPPORT);
993
- } catch (Exception ex) {
994
- Log.d(LOG_TAG, "getMaxTransceiveLength fail");
995
- callback.invoke(ex.toString());
996
- }
997
- } else {
998
- callback.invoke(ERR_NO_TECH_REQ);
999
- }
403
+ NfcTechIoRouter.getMaxTransceiveLength(techRequest, callback);
1000
404
  }
1001
405
  }
1002
406
 
1003
407
  @ReactMethod
1004
408
  public void cancelNdefWrite(Callback callback) {
1005
409
  synchronized(this) {
1006
- if (writeNdefRequest != null) {
1007
- writeNdefRequest.callback.invoke(ERR_CANCEL);
1008
- writeNdefRequest = null;
1009
- callback.invoke();
1010
- } else {
1011
- callback.invoke(ERR_NOT_REGISTERED);
1012
- }
410
+ writeNdefRequest = NdefHandler.cancelNdefWrite(writeNdefRequest, callback);
1013
411
  }
1014
412
  }
1015
413
 
1016
414
  @ReactMethod
1017
415
  public void requestNdefWrite(ReadableArray rnArray, ReadableMap options, Callback callback) {
1018
416
  synchronized(this) {
1019
- if (!isForegroundEnabled) {
1020
- callback.invoke(ERR_NOT_REGISTERED);
1021
- return;
1022
- }
1023
-
1024
- if (hasPendingRequest()) {
1025
- callback.invoke(ERR_MULTI_REQ);
1026
- } else {
1027
- boolean format = options.getBoolean("format");
1028
- boolean formatReadOnly = options.getBoolean("formatReadOnly");
1029
-
1030
- try {
1031
- NdefMessage msgToWrite;
1032
-
1033
- /// the only case we allow ndef message to be null is when formatting, see:
1034
- /// https://developer.android.com/reference/android/nfc/tech/NdefFormatable.html#format(android.nfc.NdefMessage)
1035
- /// this API allows the `firstMessage` to be null
1036
- if (format && rnArray == null) {
1037
- msgToWrite = null;
1038
- } else {
1039
- byte[] bytes = rnArrayToBytes(rnArray);
1040
- msgToWrite = new NdefMessage(bytes);
1041
- }
1042
-
1043
- writeNdefRequest = new WriteNdefRequest(
1044
- msgToWrite,
1045
- callback, // defer the callback
1046
- format,
1047
- formatReadOnly
1048
- );
1049
- } catch (FormatException e) {
1050
- callback.invoke(e.toString());
1051
- }
1052
- }
417
+ writeNdefRequest = NdefHandler.requestNdefWrite(
418
+ rnArray,
419
+ options,
420
+ isForegroundEnabled,
421
+ hasPendingRequest(),
422
+ writeNdefRequest,
423
+ callback
424
+ );
1053
425
  }
1054
426
  }
1055
427
 
1056
428
  @ReactMethod
1057
429
  public void start(Callback callback) {
1058
- NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(context);
1059
- if (nfcAdapter != null) {
1060
- Log.d(LOG_TAG, "start");
430
+ synchronized(this) {
431
+ var context = getReactApplicationContext();
432
+ NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(context);
433
+ if (nfcAdapter == null) {
434
+ Log.d(LOG_TAG, "not support in this device");
435
+ callback.invoke(ERR_NO_NFC_SUPPORT);
436
+ return;
437
+ }
1061
438
 
1062
- IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
439
+ Log.d(LOG_TAG, "start");
1063
440
  Activity currentActivity = context.getCurrentActivity();
1064
441
  if (currentActivity == null) {
1065
442
  callback.invoke(ERR_GET_ACTIVITY_FAIL);
1066
443
  return;
1067
444
  }
1068
445
 
1069
- currentActivity.registerReceiver(mReceiver, filter);
1070
- Intent launchIntent = currentActivity.getIntent();
1071
- // we consider the launching intent to be background
1072
- bgTag = parseNfcIntent(launchIntent);
446
+ try {
447
+ if (receiverActivity == null) {
448
+ IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
449
+ currentActivity.registerReceiver(mReceiver, filter);
450
+ receiverActivity = currentActivity;
451
+ }
452
+ Intent launchIntent = currentActivity.getIntent();
453
+ // we consider the launching intent to be background
454
+ bgTag = parseNfcIntent(launchIntent);
455
+ } catch (Exception ex) {
456
+ callback.invoke(ex.toString());
457
+ return;
458
+ }
1073
459
  callback.invoke();
1074
- } else {
1075
- Log.d(LOG_TAG, "not support in this device");
1076
- callback.invoke(ERR_NO_NFC_SUPPORT);
1077
460
  }
1078
461
  }
1079
462
 
1080
463
  @ReactMethod
1081
464
  public void isSupported(String tech, Callback callback){
1082
465
  Log.d(LOG_TAG, "isSupported");
1083
- Activity currentActivity = context.getCurrentActivity();
466
+ Activity currentActivity = getReactApplicationContext().getCurrentActivity();
1084
467
  if (currentActivity == null) {
1085
468
  callback.invoke(ERR_GET_ACTIVITY_FAIL);
1086
469
  return;
@@ -1095,7 +478,7 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
1095
478
  // compatible with MifareClassic
1096
479
  // TODO: Check if it's the same case with MifareUltralight
1097
480
  if (tech.equals("MifareClassic")) {
1098
- if (!MifareUtil.isDeviceSupported(currentActivity)) {
481
+ if (!Util.isDeviceSupported(currentActivity)) {
1099
482
  callback.invoke(null, false);
1100
483
  return;
1101
484
  }
@@ -1107,7 +490,7 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
1107
490
  @ReactMethod
1108
491
  public void isEnabled(Callback callback) {
1109
492
  Log.d(LOG_TAG, "isEnabled");
1110
- NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(context);
493
+ NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getReactApplicationContext());
1111
494
  if (nfcAdapter != null) {
1112
495
  callback.invoke(null, nfcAdapter.isEnabled());
1113
496
  } else {
@@ -1118,7 +501,7 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
1118
501
  @ReactMethod
1119
502
  public void goToNfcSetting(Callback callback) {
1120
503
  Log.d(LOG_TAG, "goToNfcSetting");
1121
- Activity currentActivity = context.getCurrentActivity();
504
+ Activity currentActivity = getReactApplicationContext().getCurrentActivity();
1122
505
  if (currentActivity == null) {
1123
506
  callback.invoke(ERR_GET_ACTIVITY_FAIL);
1124
507
  return;
@@ -1134,7 +517,7 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
1134
517
 
1135
518
  @ReactMethod
1136
519
  public void getLaunchTagEvent(Callback callback) {
1137
- Activity currentActivity = context.getCurrentActivity();
520
+ Activity currentActivity = getReactApplicationContext().getCurrentActivity();
1138
521
  if (currentActivity == null) {
1139
522
  callback.invoke(ERR_GET_ACTIVITY_FAIL);
1140
523
  return;
@@ -1156,66 +539,47 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
1156
539
  callback.invoke();
1157
540
  }
1158
541
 
1159
- @Override
1160
- public void restartTechnologyRequest(Callback callback) {
1161
-
1162
- }
1163
-
1164
- @Override
1165
- public void invalidateSession(Callback callback) {
1166
-
1167
- }
1168
-
1169
- @Override
1170
- public void invalidateSessionWithError(String message, Callback callback) {
1171
-
1172
- }
1173
-
1174
542
  @ReactMethod
1175
543
  public void registerTagEvent(ReadableMap options, Callback callback) {
1176
- isReaderModeEnabled = options.getBoolean("isReaderModeEnabled");
1177
- readerModeFlags = options.getInt("readerModeFlags");
1178
- readerModeDelay = options.getInt("readerModeDelay");
1179
-
1180
- Log.d(LOG_TAG, "registerTagEvent");
1181
- isForegroundEnabled = true;
1182
-
1183
- // capture all mime-based dispatch NDEF
1184
- IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
1185
- try {
1186
- ndef.addDataType("*/*");
1187
- } catch (MalformedMimeTypeException e) {
1188
- throw new RuntimeException("fail", e);
1189
- }
1190
- intentFilters.add(ndef);
544
+ synchronized(this) {
545
+ Log.d(LOG_TAG, "registerTagEvent");
546
+ IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
547
+ try {
548
+ // capture all mime-based dispatch NDEF
549
+ ndef.addDataType("*/*");
550
+ } catch (MalformedMimeTypeException ex) {
551
+ callback.invoke(ex.toString());
552
+ return;
553
+ }
1191
554
 
1192
- // capture all rest NDEF, such as uri-based
1193
- intentFilters.add(new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED));
1194
- techLists.add(new String[]{Ndef.class.getName()});
555
+ intentFilters.clear();
556
+ techLists.clear();
557
+ intentFilters.add(ndef);
558
+ // capture all rest NDEF, such as uri-based
559
+ intentFilters.add(new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED));
560
+ techLists.add(new String[]{Ndef.class.getName()});
561
+ // for those without NDEF, get them as tags
562
+ intentFilters.add(new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED));
1195
563
 
1196
- // for those without NDEF, get them as tags
1197
- intentFilters.add(new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED));
564
+ isReaderModeEnabled = options.getBoolean("isReaderModeEnabled");
565
+ readerModeFlags = options.getInt("readerModeFlags");
566
+ readerModeDelay = options.getInt("readerModeDelay");
567
+ isForegroundEnabled = true;
1198
568
 
1199
- if (isResumed) {
1200
- enableDisableForegroundDispatch(true);
569
+ if (isResumed) {
570
+ enableDisableForegroundDispatch(true);
571
+ }
572
+ callback.invoke();
1201
573
  }
1202
- callback.invoke();
1203
574
  }
1204
575
 
1205
576
  @ReactMethod
1206
577
  public void unregisterTagEvent(Callback callback) {
1207
- Log.d(LOG_TAG, "unregisterTagEvent");
1208
- if (isResumed) {
1209
- enableDisableForegroundDispatch(false);
578
+ synchronized(this) {
579
+ Log.d(LOG_TAG, "unregisterTagEvent");
580
+ resetTagRegistration();
581
+ callback.invoke();
1210
582
  }
1211
-
1212
- intentFilters.clear();
1213
- isForegroundEnabled = false;
1214
- isReaderModeEnabled = false;
1215
- readerModeFlags = 0;
1216
- readerModeDelay = 0;
1217
-
1218
- callback.invoke();
1219
583
  }
1220
584
 
1221
585
  @ReactMethod
@@ -1235,123 +599,121 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
1235
599
  }
1236
600
 
1237
601
  @Override
1238
- public void iso15693_getSystemInfo(double requestFlag, Callback callback) {
1239
-
1240
- }
1241
-
1242
- @Override
1243
- public void iso15693_readSingleBlock(ReadableMap options, Callback callback) {
1244
-
1245
- }
1246
-
1247
- @Override
1248
- public void iso15693_readMultipleBlocks(ReadableMap options, Callback callback) {
1249
-
1250
- }
1251
-
1252
- @Override
1253
- public void iso15693_writeSingleBlock(ReadableMap options, Callback callback) {
1254
-
1255
- }
1256
-
1257
- @Override
1258
- public void iso15693_lockBlock(ReadableMap options, Callback callback) {
1259
-
1260
- }
1261
-
1262
- @Override
1263
- public void iso15693_writeAFI(ReadableMap options, Callback callback) {
1264
-
1265
- }
1266
-
1267
- @Override
1268
- public void iso15693_lockAFI(ReadableMap options, Callback callback) {
1269
-
1270
- }
1271
-
1272
- @Override
1273
- public void iso15693_writeDSFID(ReadableMap options, Callback callback) {
1274
-
1275
- }
1276
-
1277
- @Override
1278
- public void iso15693_lockDSFID(ReadableMap options, Callback callback) {
1279
-
602
+ public void onHostResume() {
603
+ Log.d(LOG_TAG, "onResume");
604
+ isResumed = true;
605
+ if (isForegroundEnabled) {
606
+ enableDisableForegroundDispatch(true);
607
+ }
1280
608
  }
1281
609
 
1282
610
  @Override
1283
- public void iso15693_resetToReady(ReadableMap options, Callback callback) {
1284
-
611
+ public void onHostPause() {
612
+ Log.d(LOG_TAG, "onPause");
613
+ isResumed = false;
614
+ enableDisableForegroundDispatch(false);
1285
615
  }
1286
616
 
1287
617
  @Override
1288
- public void iso15693_select(ReadableMap options, Callback callback) {
1289
-
618
+ public void onHostDestroy() {
619
+ Log.d(LOG_TAG, "onDestroy");
620
+ cleanUpNativeState();
1290
621
  }
1291
622
 
1292
623
  @Override
1293
- public void iso15693_stayQuiet(ReadableMap options, Callback callback) {
1294
-
624
+ public void invalidate() {
625
+ cleanUpNativeState();
626
+ ReactApplicationContext context = getReactApplicationContext();
627
+ context.removeActivityEventListener(this);
628
+ context.removeLifecycleEventListener(this);
629
+ super.invalidate();
1295
630
  }
1296
631
 
1297
632
  @Override
1298
- public void iso15693_customCommand(ReadableMap options, Callback callback) {
1299
-
633
+ public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
634
+ Log.d(LOG_TAG, "onActivityResult");
1300
635
  }
1301
636
 
1302
637
  @Override
1303
- public void iso15693_sendRequest(ReadableMap options, Callback callback) {
1304
-
638
+ public void onNewIntent(Intent intent) {
639
+ Log.d(LOG_TAG, "onNewIntent " + intent);
640
+ WritableMap nfcTag = parseNfcIntent(intent);
641
+ if (nfcTag != null) {
642
+ if (isForegroundEnabled) {
643
+ sendEvent("NfcManagerDiscoverTag", nfcTag);
644
+ } else {
645
+ sendEvent("NfcManagerDiscoverBackgroundTag", nfcTag);
646
+ bgTag = nfcTag;
647
+ }
648
+ }
1305
649
  }
1306
650
 
1307
- @Override
1308
- public void iso15693_extendedReadSingleBlock(ReadableMap options, Callback callback) {
1309
-
651
+ private boolean hasPendingRequest() {
652
+ return writeNdefRequest != null || techRequest != null;
1310
653
  }
1311
654
 
1312
- @Override
1313
- public void iso15693_extendedReadMultipleBlocks(ReadableMap options, Callback callback) {
1314
-
655
+ private TagTechnologyRequest detachTechnologyRequest() {
656
+ TagTechnologyRequest request = techRequest;
657
+ techRequest = null;
658
+ return request;
1315
659
  }
1316
660
 
1317
- @Override
1318
- public void iso15693_extendedWriteSingleBlock(ReadableMap options, Callback callback) {
1319
-
661
+ private void resetTagRegistration() {
662
+ if (isResumed) {
663
+ enableDisableForegroundDispatch(false);
664
+ }
665
+ intentFilters.clear();
666
+ techLists.clear();
667
+ isForegroundEnabled = false;
668
+ isReaderModeEnabled = false;
669
+ readerModeFlags = 0;
670
+ readerModeDelay = 0;
1320
671
  }
1321
672
 
1322
- @Override
1323
- public void iso15693_extendedLockBlock(ReadableMap options, Callback callback) {
673
+ private void cleanUpNativeState() {
674
+ synchronized(this) {
675
+ resetTagRegistration();
676
+ isResumed = false;
1324
677
 
1325
- }
678
+ TagTechnologyRequest request = detachTechnologyRequest();
679
+ if (request != null) {
680
+ request.close();
681
+ try {
682
+ request.invokePendingCallbackWithError(ERR_CANCEL);
683
+ } catch (RuntimeException ex) {
684
+ Log.w(LOG_TAG, "fail to complete destroyed technology request", ex);
685
+ }
686
+ }
1326
687
 
688
+ NdefHandler.WriteNdefRequest ndefRequest = writeNdefRequest;
689
+ writeNdefRequest = null;
690
+ if (ndefRequest != null) {
691
+ try {
692
+ ndefRequest.invokeCallbackWithError(ERR_CANCEL);
693
+ } catch (RuntimeException ex) {
694
+ Log.w(LOG_TAG, "fail to complete destroyed NDEF request", ex);
695
+ }
696
+ }
1327
697
 
698
+ if (receiverActivity != null) {
699
+ try {
700
+ receiverActivity.unregisterReceiver(mReceiver);
701
+ } catch (IllegalArgumentException ex) {
702
+ Log.w(LOG_TAG, "adapter-state receiver was already unregistered", ex);
703
+ }
704
+ receiverActivity = null;
705
+ }
1328
706
 
1329
- @Override
1330
- public void onHostResume() {
1331
- Log.d(LOG_TAG, "onResume");
1332
- isResumed = true;
1333
- if (isForegroundEnabled) {
1334
- enableDisableForegroundDispatch(true);
707
+ tag = null;
708
+ bgTag = null;
1335
709
  }
1336
710
  }
1337
711
 
1338
- @Override
1339
- public void onHostPause() {
1340
- Log.d(LOG_TAG, "onPause");
1341
- isResumed = false;
1342
- enableDisableForegroundDispatch(false);
1343
- }
1344
-
1345
- @Override
1346
- public void onHostDestroy() {
1347
- Log.d(LOG_TAG, "onDestroy");
1348
- }
1349
-
1350
712
  private void enableDisableForegroundDispatch(boolean enable) {
1351
713
  Log.i(LOG_TAG, "enableForegroundDispatch, enable = " + enable);
714
+ var context = getReactApplicationContext();
1352
715
  NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(context);
1353
716
  Activity currentActivity = context.getCurrentActivity();
1354
- final NfcManager manager = this;
1355
717
  if (nfcAdapter != null && currentActivity != null && !currentActivity.isFinishing()) {
1356
718
  try {
1357
719
  if (isReaderModeEnabled) {
@@ -1359,36 +721,7 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
1359
721
  Log.i(LOG_TAG, String.format("enableReaderMode, flags: %d, delay: %d ms", readerModeFlags, readerModeDelay));
1360
722
  Bundle readerModeExtras = new Bundle();
1361
723
  readerModeExtras.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, readerModeDelay);
1362
- nfcAdapter.enableReaderMode(currentActivity, new NfcAdapter.ReaderCallback() {
1363
- @Override
1364
- public void onTagDiscovered(Tag tag) {
1365
- synchronized (this) {
1366
- manager.tag = tag;
1367
- Log.d(LOG_TAG, "readerMode onTagDiscovered");
1368
- WritableMap nfcTag;
1369
- // if the tag contains NDEF, we want to report the content
1370
- if (Arrays.asList(tag.getTechList()).contains(Ndef.class.getName())) {
1371
- Ndef ndef = Ndef.get(tag);
1372
- nfcTag = ndef2React(ndef, new NdefMessage[] { ndef.getCachedNdefMessage() });
1373
- } else {
1374
- nfcTag = tag2React(tag);
1375
- }
1376
-
1377
- if (nfcTag != null) {
1378
- sendEvent("NfcManagerDiscoverTag", nfcTag);
1379
- if (techRequest!= null && !techRequest.isConnected()) {
1380
- boolean result = techRequest.connect(tag);
1381
- if (result) {
1382
- techRequest.invokePendingCallback(techRequest.getTechType());
1383
- } else {
1384
- // this indicates that we get a NFC tag, but none of the user required tech is matched
1385
- techRequest.invokePendingCallback(null);
1386
- }
1387
- }
1388
- }
1389
- }
1390
- }
1391
- }, readerModeFlags, readerModeExtras);
724
+ nfcAdapter.enableReaderMode(currentActivity, this::handleReaderModeTagDiscovered, readerModeFlags, readerModeExtras);
1392
725
  } else {
1393
726
  Log.i(LOG_TAG, "disableReaderMode");
1394
727
  nfcAdapter.disableReaderMode(currentActivity);
@@ -1406,8 +739,33 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
1406
739
  }
1407
740
  }
1408
741
 
742
+ private void handleReaderModeTagDiscovered(Tag tag) {
743
+ synchronized (this) {
744
+ this.tag = tag;
745
+ Log.d(LOG_TAG, "readerMode onTagDiscovered");
746
+ WritableMap nfcTag;
747
+ if (Arrays.asList(tag.getTechList()).contains(Ndef.class.getName())) {
748
+ nfcTag = NdefHandler.ndefToReact(tag);
749
+ } else {
750
+ nfcTag = Util.tagToReact(tag);
751
+ }
752
+
753
+ if (nfcTag != null) {
754
+ sendEvent("NfcManagerDiscoverTag", nfcTag);
755
+ if (techRequest != null && !techRequest.isConnected()) {
756
+ boolean result = techRequest.connect(tag);
757
+ if (result) {
758
+ techRequest.invokePendingCallback(techRequest.getTechType());
759
+ } else {
760
+ techRequest.invokePendingCallback(null);
761
+ }
762
+ }
763
+ }
764
+ }
765
+ }
766
+
1409
767
  private PendingIntent getPendingIntent() {
1410
- Activity activity = context.getCurrentActivity();
768
+ Activity activity = getReactApplicationContext().getCurrentActivity();
1411
769
  assert activity != null;
1412
770
  Intent intent = new Intent(activity, activity.getClass());
1413
771
  intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -1429,63 +787,35 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
1429
787
 
1430
788
  private void sendEvent(String eventName,
1431
789
  @Nullable WritableMap params) {
790
+ if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
791
+ WritableMap eventPayload = params != null ? params : Arguments.createMap();
792
+ switch (eventName) {
793
+ case "NfcManagerDiscoverTag":
794
+ emitOnDiscoverTag(eventPayload);
795
+ return;
796
+ case "NfcManagerDiscoverBackgroundTag":
797
+ emitOnDiscoverBackgroundTag(eventPayload);
798
+ return;
799
+ case "NfcManagerStateChanged":
800
+ emitOnStateChanged(eventPayload);
801
+ return;
802
+ default:
803
+ Log.w(LOG_TAG, "unknown NFC event: " + eventName);
804
+ return;
805
+ }
806
+ }
1432
807
  getReactApplicationContext()
1433
808
  .getJSModule(RCTNativeAppEventEmitter.class)
1434
809
  .emit(eventName, params);
1435
810
  }
1436
811
 
1437
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1438
- @Override
1439
- public void onReceive(Context context, Intent intent) {
1440
- Log.d(LOG_TAG, "onReceive " + intent);
1441
- final String action = intent.getAction();
1442
-
1443
- if (action.equals(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED)) {
1444
- final int state = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE,
1445
- NfcAdapter.STATE_OFF);
1446
- String stateStr = "unknown";
1447
- switch (state) {
1448
- case NfcAdapter.STATE_OFF:
1449
- stateStr = "off";
1450
- break;
1451
- case NfcAdapter.STATE_TURNING_OFF:
1452
- stateStr = "turning_off";
1453
- break;
1454
- case NfcAdapter.STATE_ON:
1455
- stateStr = "on";
1456
- break;
1457
- case NfcAdapter.STATE_TURNING_ON:
1458
- stateStr = "turning_on";
1459
- break;
1460
- }
1461
-
1462
- try {
1463
- WritableMap writableMap = Arguments.createMap();
1464
- writableMap.putString("state", stateStr);
1465
- sendEvent("NfcManagerStateChanged", writableMap);
1466
- } catch (Exception ex) {
1467
- Log.d(LOG_TAG, "send nfc state change event fail: " + ex);
1468
- }
1469
- }
1470
- }
1471
- };
1472
-
1473
- @Override
1474
- public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
1475
- Log.d(LOG_TAG, "onActivityResult");
1476
- }
1477
-
1478
- @Override
1479
- public void onNewIntent(Intent intent) {
1480
- Log.d(LOG_TAG, "onNewIntent " + intent);
1481
- WritableMap nfcTag = parseNfcIntent(intent);
1482
- if (nfcTag != null) {
1483
- if (isForegroundEnabled) {
1484
- sendEvent("NfcManagerDiscoverTag", nfcTag);
1485
- } else {
1486
- sendEvent("NfcManagerDiscoverBackgroundTag", nfcTag);
1487
- bgTag = nfcTag;
1488
- }
812
+ private void emitAdapterStateChanged(String stateStr) {
813
+ try {
814
+ WritableMap writableMap = Arguments.createMap();
815
+ writableMap.putString("state", stateStr);
816
+ sendEvent("NfcManagerStateChanged", writableMap);
817
+ } catch (Exception ex) {
818
+ Log.d(LOG_TAG, "send nfc state change event fail: " + ex);
1489
819
  }
1490
820
  }
1491
821
 
@@ -1507,11 +837,9 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
1507
837
  synchronized(this) {
1508
838
  this.tag = tag;
1509
839
  if (writeNdefRequest != null) {
1510
- writeNdef(
1511
- tag,
1512
- writeNdefRequest
1513
- );
840
+ NdefHandler.WriteNdefRequest request = writeNdefRequest;
1514
841
  writeNdefRequest = null;
842
+ NdefHandler.writeNdef(tag, request);
1515
843
 
1516
844
  // explicitly return null, to avoid extra detection
1517
845
  return null;
@@ -1531,139 +859,25 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
1531
859
  }
1532
860
  }
1533
861
 
1534
- Ndef ndef;
1535
862
  switch (action) {
1536
863
  case NfcAdapter.ACTION_NDEF_DISCOVERED:
1537
- ndef = Ndef.get(tag);
1538
864
  Parcelable[] messages = intent.getParcelableArrayExtra((NfcAdapter.EXTRA_NDEF_MESSAGES));
1539
- parsed = ndef2React(ndef, messages);
865
+ parsed = NdefHandler.ndefToReact(tag, messages);
1540
866
  break;
1541
867
  case NfcAdapter.ACTION_TECH_DISCOVERED:
1542
868
  // if the tag contains NDEF, we want to report the content
1543
869
  if (Arrays.asList(tag.getTechList()).contains(Ndef.class.getName())) {
1544
- ndef = Ndef.get(tag);
1545
- parsed = ndef2React(ndef, new NdefMessage[]{ndef.getCachedNdefMessage()});
870
+ parsed = NdefHandler.ndefToReact(tag);
1546
871
  } else {
1547
- parsed = tag2React(tag);
872
+ parsed = Util.tagToReact(tag);
1548
873
  }
1549
874
  break;
1550
875
  case NfcAdapter.ACTION_TAG_DISCOVERED:
1551
- parsed = tag2React(tag);
876
+ parsed = Util.tagToReact(tag);
1552
877
  break;
1553
878
  }
1554
879
 
1555
880
  return parsed;
1556
881
  }
1557
882
 
1558
- private WritableMap tag2React(Tag tag) {
1559
- try {
1560
- JSONObject json = Util.tagToJSON(tag);
1561
- return JsonConvert.jsonToReact(json);
1562
- } catch (JSONException ex) {
1563
- return null;
1564
- }
1565
- }
1566
-
1567
- private WritableMap ndef2React(Ndef ndef, Parcelable[] messages) {
1568
- try {
1569
- JSONObject json = buildNdefJSON(ndef, messages);
1570
- return JsonConvert.jsonToReact(json);
1571
- } catch (JSONException ex) {
1572
- return null;
1573
- }
1574
- }
1575
-
1576
- JSONObject buildNdefJSON(Ndef ndef, Parcelable[] messages) {
1577
- JSONObject json = Util.ndefToJSON(ndef);
1578
-
1579
- // ndef is null for peer-to-peer
1580
- // ndef and messages are null for ndef format-able
1581
- if (ndef == null && messages != null) {
1582
- try {
1583
-
1584
- if (messages.length > 0) {
1585
- NdefMessage message = (NdefMessage) messages[0];
1586
- json.put("ndefMessage", Util.messageToJSON(message));
1587
- // guessing type, would prefer a more definitive way to determine type
1588
- json.put("type", "NDEF");
1589
- }
1590
-
1591
- if (messages.length > 1) {
1592
- Log.d(LOG_TAG, "Expected one ndefMessage but found " + messages.length);
1593
- }
1594
-
1595
- } catch (JSONException e) {
1596
- // shouldn't happen
1597
- Log.e(Util.TAG, "Failed to convert ndefMessage into json", e);
1598
- }
1599
- }
1600
- return json;
1601
- }
1602
-
1603
- private void writeNdef(Tag tag, WriteNdefRequest request) {
1604
- NdefMessage message = request.message;
1605
- Callback callback = request.callback;
1606
- boolean formatReadOnly = request.formatReadOnly;
1607
- boolean format = request.format;
1608
-
1609
- if (format || formatReadOnly) {
1610
- try {
1611
- Log.d(LOG_TAG, "ready to writeNdef");
1612
- NdefFormatable formatable = NdefFormatable.get(tag);
1613
- if (formatable == null) {
1614
- callback.invoke(ERR_API_NOT_SUPPORT);
1615
- } else {
1616
- Log.d(LOG_TAG, "ready to format ndef, seriously");
1617
- formatable.connect();
1618
- if (formatReadOnly) {
1619
- formatable.formatReadOnly(message);
1620
- } else {
1621
- formatable.format(message);
1622
- }
1623
- callback.invoke();
1624
- }
1625
- } catch (Exception ex) {
1626
- callback.invoke(ex.toString());
1627
- }
1628
- } else {
1629
- try {
1630
- Log.d(LOG_TAG, "ready to writeNdef");
1631
- Ndef ndef = Ndef.get(tag);
1632
- if (ndef == null) {
1633
- callback.invoke(ERR_API_NOT_SUPPORT);
1634
- } else if (!ndef.isWritable()) {
1635
- callback.invoke("tag is not writeable");
1636
- } else if (ndef.getMaxSize() < message.toByteArray().length) {
1637
- callback.invoke("tag size is not enough");
1638
- } else {
1639
- Log.d(LOG_TAG, "ready to writeNdef, seriously");
1640
- ndef.connect();
1641
- ndef.writeNdefMessage(message);
1642
- callback.invoke();
1643
- }
1644
- } catch (Exception ex) {
1645
- callback.invoke(ex.toString());
1646
- }
1647
- }
1648
- }
1649
-
1650
- private static byte[] rnArrayToBytes(ReadableArray rArray) {
1651
- byte[] bytes = new byte[rArray.size()];
1652
- for (int i = 0; i < rArray.size(); i++) {
1653
- bytes[i] = (byte)(rArray.getInt(i) & 0xff);
1654
- }
1655
- return bytes;
1656
- }
1657
-
1658
- private static WritableArray bytesToRnArray(byte[] bytes) {
1659
- return appendBytesToRnArray(Arguments.createArray(), bytes);
1660
- }
1661
-
1662
- private static WritableArray appendBytesToRnArray(WritableArray value, byte[] bytes) {
1663
- for (byte aByte : bytes) {
1664
- value.pushInt((aByte & 0xFF));
1665
- }
1666
- return value;
1667
- }
1668
883
  }
1669
-