react-native-nfc-manager 4.0.0-beta.7 → 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 +37 -3
  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 +333 -1119
  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,66 +17,31 @@ 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
32
  private Boolean isForegroundEnabled = false;
49
33
  private Boolean isResumed = false;
50
- private WriteNdefRequest writeNdefRequest = null;
34
+ private NdefHandler.WriteNdefRequest writeNdefRequest = null;
51
35
  private TagTechnologyRequest techRequest = null;
52
36
  private Tag tag = null;
53
37
  private WritableMap bgTag = null;
38
+ private Activity receiverActivity = null;
54
39
  // Use NFC reader mode instead of listening to a dispatch
55
40
  private Boolean isReaderModeEnabled = false;
56
41
  private int readerModeFlags = 0;
57
42
  private int readerModeDelay = 0;
58
- private static final String ERR_CANCEL = "cancelled";
59
- private static final String ERR_NOT_REGISTERED = "you should requestTagEvent first";
60
- private static final String ERR_MULTI_REQ = "You can only issue one request at a time";
61
- private static final String ERR_NO_TECH_REQ = "no tech request available";
62
- private static final String ERR_NO_REFERENCE = "no reference available";
63
- private static final String ERR_TRANSCEIVE_FAIL = "transceive fail";
64
- private static final String ERR_API_NOT_SUPPORT = "unsupported tag api";
65
- private static final String ERR_GET_ACTIVITY_FAIL = "fail to get current activity";
66
- private static final String ERR_NO_NFC_SUPPORT = "no nfc support";
67
-
68
- static class WriteNdefRequest {
69
- NdefMessage message;
70
- Callback callback;
71
- boolean format;
72
- boolean formatReadOnly;
73
-
74
- WriteNdefRequest(NdefMessage message, Callback callback, boolean format, boolean formatReadOnly) {
75
- this.message = message;
76
- this.callback = callback;
77
- this.format = format;
78
- this.formatReadOnly = formatReadOnly;
79
- }
80
- }
43
+ private final NfcAdapterStateChangedReceiver mReceiver =
44
+ new NfcAdapterStateChangedReceiver(LOG_TAG, this::emitAdapterStateChanged);
81
45
 
82
46
  public NfcManager(ReactApplicationContext reactContext) {
83
47
  super(reactContext);
@@ -96,31 +60,23 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
96
60
  public Map<String, Object> getConstants() {
97
61
  final Map<String, Object> constants = new HashMap<>();
98
62
 
99
- constants.put("MIFARE_BLOCK_SIZE", MifareClassic.BLOCK_SIZE);
100
- constants.put("MIFARE_ULTRALIGHT_PAGE_SIZE", MifareUltralight.PAGE_SIZE);
101
- constants.put("MIFARE_ULTRALIGHT_TYPE", MifareUltralight.TYPE_ULTRALIGHT);
102
- constants.put("MIFARE_ULTRALIGHT_TYPE_C", MifareUltralight.TYPE_ULTRALIGHT_C);
103
- constants.put("MIFARE_ULTRALIGHT_TYPE_UNKNOWN", MifareUltralight.TYPE_UNKNOWN);
63
+ MifareClassicHandler.putConstants(constants);
64
+ MifareUltralightHandler.putConstants(constants);
104
65
 
105
66
  return constants;
106
67
  }
107
68
 
108
- private boolean hasPendingRequest() {
109
- return writeNdefRequest != null || techRequest != null;
110
- }
111
-
112
69
  @ReactMethod
113
70
  public void cancelTechnologyRequest(Callback callback) {
114
71
  synchronized(this) {
115
- if (techRequest != null) {
116
- techRequest.close();
72
+ TagTechnologyRequest request = detachTechnologyRequest();
73
+ if (request != null) {
74
+ request.close();
117
75
  try {
118
- techRequest.invokePendingCallbackWithError(ERR_CANCEL);
76
+ request.invokePendingCallbackWithError(ERR_CANCEL);
119
77
  } catch (RuntimeException ex) {
120
- // the pending callback might already been invoked when there is an ongoing
121
- // connected tag, bypass this case explicitly
78
+ Log.w(LOG_TAG, "fail to complete cancelled technology request", ex);
122
79
  }
123
- techRequest = null;
124
80
  }
125
81
  callback.invoke();
126
82
  }
@@ -145,9 +101,14 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
145
101
  @ReactMethod
146
102
  public void closeTechnology(Callback callback) {
147
103
  synchronized(this) {
148
- if (techRequest != null) {
149
- techRequest.close();
150
- 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
+ }
151
112
  }
152
113
  callback.invoke();
153
114
  }
@@ -159,11 +120,10 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
159
120
  if (techRequest != null) {
160
121
  Tag tag = techRequest.getTagHandle();
161
122
  if (tag != null) {
162
- WritableMap parsed = tag2React(tag);
123
+ WritableMap parsed = Util.tagToReact(tag);
163
124
  if (Arrays.asList(tag.getTechList()).contains(Ndef.class.getName())) {
164
125
  try {
165
- Ndef ndef = Ndef.get(tag);
166
- parsed = ndef2React(ndef, new NdefMessage[]{ndef.getCachedNdefMessage()});
126
+ parsed = NdefHandler.ndefToReact(tag);
167
127
  } catch (Exception ex) {
168
128
  Log.d(LOG_TAG, ex.toString());
169
129
  }
@@ -181,898 +141,322 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
181
141
  @ReactMethod
182
142
  public void getCachedNdefMessage(Callback callback) {
183
143
  synchronized(this) {
184
- if (techRequest != null) {
185
- try {
186
- Ndef ndef = Ndef.get(techRequest.getTagHandle());
187
- WritableMap parsed = ndef2React(ndef, new NdefMessage[] { ndef.getCachedNdefMessage() });
188
- callback.invoke(null, parsed);
189
- } catch (Exception ex) {
190
- Log.d(LOG_TAG, ex.toString());
191
- callback.invoke(ex.toString());
192
- }
193
- } else {
194
- callback.invoke(ERR_NO_TECH_REQ);
195
- }
144
+ NdefHandler.getCachedNdefMessage(techRequest, callback);
196
145
  }
197
146
  }
198
147
 
199
148
  @ReactMethod
200
149
  public void getNdefMessage(Callback callback) {
201
150
  synchronized(this) {
202
- if (techRequest != null) {
203
- try {
204
- Ndef ndef = Ndef.get(techRequest.getTagHandle());
205
- WritableMap parsed = ndef2React(null, new NdefMessage[] { ndef.getNdefMessage() });
206
- callback.invoke(null, parsed);
207
- } catch (Exception ex) {
208
- Log.d(LOG_TAG, ex.toString());
209
- callback.invoke(ex.toString());
210
- }
211
- } else {
212
- callback.invoke(ERR_NO_TECH_REQ);
213
- }
151
+ NdefHandler.getNdefMessage(techRequest, callback);
214
152
  }
215
153
  }
216
154
 
217
155
  @ReactMethod
218
156
  public void queryNdefStatus(Callback callback) {
219
157
  synchronized(this) {
220
- if (techRequest != null) {
221
- WritableMap writableMap = Arguments.createMap();
222
- try {
223
- Ndef ndef = Ndef.get(techRequest.getTagHandle());
224
- int maxSize = ndef.getMaxSize();
225
- boolean isWritable = ndef.isWritable();
226
- boolean canMakeReadOnly = ndef.canMakeReadOnly();
227
- writableMap.putInt("maxSize", maxSize);
228
- writableMap.putBoolean("isWritable", isWritable);
229
- writableMap.putBoolean("canMakeReadOnly", canMakeReadOnly);
230
- callback.invoke(null, writableMap);
231
- } catch (Exception ex) {
232
- Log.d(LOG_TAG, ex.toString());
233
- callback.invoke(ex.toString());
234
- }
235
- } else {
236
- callback.invoke(ERR_NO_TECH_REQ);
237
- }
158
+ NdefHandler.queryNdefStatus(techRequest, callback);
238
159
  }
239
160
  }
240
161
 
241
162
  @ReactMethod
242
163
  public void writeNdefMessage(ReadableArray rnArray, ReadableMap options, Callback callback) {
243
164
  synchronized(this) {
244
- boolean reconnectAfterWrite = options.getBoolean("reconnectAfterWrite");
245
-
246
- if (techRequest != null) {
247
- try {
248
- Ndef ndef = (Ndef)techRequest.getTechHandle();
249
- if (ndef == null) {
250
- callback.invoke(ERR_API_NOT_SUPPORT);
251
- } else {
252
- byte[] bytes = rnArrayToBytes(rnArray);
253
- ndef.writeNdefMessage(new NdefMessage(bytes));
254
- if (reconnectAfterWrite) {
255
- ndef.close();
256
- //reconnection is needed in order to be able to read the written ndef
257
- ndef.connect();
258
- }
259
- callback.invoke();
260
- }
261
- } catch (Exception ex) {
262
- Log.d(LOG_TAG, ex.toString());
263
- callback.invoke(ex.toString());
264
- }
265
- } else {
266
- callback.invoke(ERR_NO_TECH_REQ);
267
- }
165
+ NdefHandler.writeNdefMessage(
166
+ techRequest,
167
+ rnArray,
168
+ options,
169
+ callback
170
+ );
268
171
  }
269
172
  }
270
173
 
271
174
  @ReactMethod
272
175
  public void formatNdef(ReadableArray rnArray, ReadableMap options, Callback callback) {
273
- boolean readOnly = options.getBoolean("readOnly");
274
-
275
176
  synchronized(this) {
276
- if (techRequest != null) {
277
- try {
278
- NdefFormatable ndef = (NdefFormatable)techRequest.getTechHandle();
279
- if (ndef == null) {
280
- callback.invoke(ERR_API_NOT_SUPPORT);
281
- } else {
282
- byte[] bytes = rnArrayToBytes(rnArray);
283
- NdefMessage msg = new NdefMessage(bytes);
284
- if (readOnly) {
285
- ndef.formatReadOnly(msg);
286
- } else {
287
- ndef.format(msg);
288
- }
289
- callback.invoke();
290
- }
291
- } catch (Exception ex) {
292
- Log.d(LOG_TAG, ex.toString());
293
- callback.invoke(ex.toString());
294
- }
295
- } else {
296
- callback.invoke(ERR_NO_TECH_REQ);
297
- }
298
- }
299
- }
300
-
301
- private void mifareClassicAuthenticate(char type, int sector, ReadableArray key, Callback callback) {
302
- if (techRequest != null) {
303
- try {
304
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
305
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
306
- // Not a mifare card, fail
307
- callback.invoke("mifareClassicAuthenticate fail: TYPE_UNKNOWN");
308
- return;
309
- } else if (sector >= mifareTag.getSectorCount()) {
310
- // Check if in range
311
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicAuthenticate fail: invalid sector %d (max %d)", sector, mifareTag.getSectorCount());
312
- callback.invoke(msg);
313
- return;
314
- } else if (key.size() != 6) {
315
- // Invalid key length
316
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicAuthenticate fail: invalid key (needs length 6 but has %d characters)", key.size());
317
- callback.invoke(msg);
318
- return;
319
- }
320
-
321
- boolean result;
322
- if (type == 'A') {
323
- result = mifareTag.authenticateSectorWithKeyA(sector, rnArrayToBytes(key));
324
- } else {
325
- result = mifareTag.authenticateSectorWithKeyB(sector, rnArrayToBytes(key));
326
- }
327
-
328
- if (!result) {
329
- callback.invoke("mifareClassicAuthenticate fail: AUTH_FAIL");
330
- return;
331
- }
332
-
333
- callback.invoke(null, true);
334
- } catch (TagLostException ex) {
335
- callback.invoke("mifareClassicAuthenticate fail: TAG_LOST");
336
- } catch (Exception ex) {
337
- callback.invoke("mifareClassicAuthenticate fail: " + ex);
338
- }
339
- } else {
340
- callback.invoke(ERR_NO_TECH_REQ);
177
+ NdefHandler.formatNdef(
178
+ techRequest,
179
+ rnArray,
180
+ options,
181
+ callback
182
+ );
341
183
  }
342
184
  }
343
185
 
344
186
  @ReactMethod
345
187
  public void mifareClassicAuthenticateA(double sector, ReadableArray key, Callback callback) {
346
188
  synchronized(this) {
347
- mifareClassicAuthenticate('A', (int)sector, key, callback);
189
+ MifareClassicHandler.authenticate(techRequest, 'A', (int)sector, key, callback);
348
190
  }
349
191
  }
350
192
 
351
193
  @ReactMethod
352
194
  public void mifareClassicAuthenticateB(double sector, ReadableArray key, Callback callback) {
353
195
  synchronized(this) {
354
- mifareClassicAuthenticate('B', (int)sector, key, callback);
196
+ MifareClassicHandler.authenticate(techRequest, 'B', (int)sector, key, callback);
355
197
  }
356
198
  }
357
199
 
358
200
  @ReactMethod
359
201
  public void mifareClassicGetBlockCountInSector(double _sectorIndex, Callback callback) {
360
- int sectorIndex = (int)_sectorIndex;
361
202
  synchronized(this) {
362
- if (techRequest != null) {
363
- try {
364
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
365
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
366
- // Not a mifare card, fail
367
- callback.invoke("mifareClassicGetBlockCountInSector fail: TYPE_UNKNOWN");
368
- return;
369
- } else if (sectorIndex >= mifareTag.getSectorCount()) {
370
- // Check if in range
371
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicGetBlockCountInSector fail: invalid sector %d (max %d)", sectorIndex, mifareTag.getSectorCount());
372
- callback.invoke(msg);
373
- return;
374
- }
375
-
376
- callback.invoke(null, mifareTag.getBlockCountInSector(sectorIndex));
377
- } catch (Exception ex) {
378
- callback.invoke("mifareClassicGetBlockCountInSector fail: " + ex);
379
- }
380
- } else {
381
- callback.invoke(ERR_NO_TECH_REQ);
382
- }
203
+ MifareClassicHandler.getBlockCountInSector(
204
+ techRequest,
205
+ (int)_sectorIndex,
206
+ callback
207
+ );
383
208
  }
384
209
  }
385
210
 
386
211
  @ReactMethod
387
212
  public void mifareClassicGetSectorCount(Callback callback) {
388
213
  synchronized(this) {
389
- if (techRequest != null) {
390
- try {
391
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
392
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
393
- // Not a mifare card, fail
394
- callback.invoke("mifareClassicGetSectorCount fail: TYPE_UNKNOWN");
395
- return;
396
- }
397
-
398
- callback.invoke(null, mifareTag.getSectorCount());
399
- } catch (Exception ex) {
400
- callback.invoke("mifareClassicGetSectorCount fail: " + ex);
401
- }
402
- } else {
403
- callback.invoke(ERR_NO_TECH_REQ);
404
- }
214
+ MifareClassicHandler.getSectorCount(techRequest, callback);
405
215
  }
406
216
  }
407
217
 
408
218
  @ReactMethod
409
219
  public void mifareClassicSectorToBlock(double _sectorIndex, Callback callback) {
410
- int sectorIndex = (int)_sectorIndex;
411
220
  synchronized(this) {
412
- if (techRequest != null) {
413
- try {
414
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
415
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
416
- // Not a mifare card, fail
417
- callback.invoke("mifareClassicSectorToBlock fail: TYPE_UNKNOWN");
418
- return;
419
- } else if (sectorIndex >= mifareTag.getSectorCount()) {
420
- // Check if in range
421
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicSectorToBlock fail: invalid sector %d (max %d)", sectorIndex, mifareTag.getSectorCount());
422
- callback.invoke(msg);
423
- return;
424
- }
425
-
426
- callback.invoke(null, mifareTag.sectorToBlock(sectorIndex));
427
- } catch (Exception ex) {
428
- callback.invoke("mifareClassicSectorToBlock fail: " + ex);
429
- }
430
- } else {
431
- callback.invoke(ERR_NO_TECH_REQ);
432
- }
221
+ MifareClassicHandler.sectorToBlock(
222
+ techRequest,
223
+ (int)_sectorIndex,
224
+ callback
225
+ );
433
226
  }
434
227
  }
435
228
 
436
229
  @ReactMethod
437
230
  public void mifareClassicReadBlock(double _blockIndex, Callback callback) {
438
- int blockIndex = (int)_blockIndex;
439
231
  synchronized(this) {
440
- if (techRequest != null) {
441
- try {
442
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
443
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
444
- // Not a mifare card, fail
445
- callback.invoke("mifareClassicReadBlock fail: TYPE_UNKNOWN");
446
- return;
447
- } else if (blockIndex >= mifareTag.getBlockCount()) {
448
- // Check if in range
449
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicReadBlock fail: invalid block %d (max %d)", blockIndex, mifareTag.getBlockCount());
450
- callback.invoke(msg);
451
- return;
452
- }
453
-
454
- byte[] buffer = mifareTag.readBlock(blockIndex);
455
-
456
- WritableArray result = bytesToRnArray(buffer);
457
- callback.invoke(null, result);
458
- } catch (TagLostException ex) {
459
- callback.invoke("mifareClassicReadBlock fail: TAG_LOST");
460
- } catch (Exception ex) {
461
- callback.invoke("mifareClassicReadBlock fail: " + ex);
462
- }
463
- } else {
464
- callback.invoke(ERR_NO_TECH_REQ);
465
- }
232
+ MifareClassicHandler.readBlock(
233
+ techRequest,
234
+ (int)_blockIndex,
235
+ callback
236
+ );
466
237
  }
467
238
  }
468
239
 
469
240
  @ReactMethod
470
241
  public void mifareClassicReadSector(double _sectorIndex, Callback callback) {
471
- int sectorIndex = (int)_sectorIndex;
472
242
  synchronized(this) {
473
- if (techRequest != null) {
474
- try {
475
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
476
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
477
- // Not a mifare card, fail
478
- callback.invoke("mifareClassicReadSector fail: TYPE_UNKNOWN");
479
- return;
480
- } else if (sectorIndex >= mifareTag.getSectorCount()) {
481
- // Check if in range
482
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicReadSector fail: invalid sector %d (max %d)", sectorIndex, mifareTag.getSectorCount());
483
- callback.invoke(msg);
484
- return;
485
- }
486
-
487
- WritableArray result = Arguments.createArray();
488
- int blocks = mifareTag.getBlockCountInSector(sectorIndex);
489
- byte[] buffer;
490
- for (int i = 0; i < blocks; i++) {
491
- buffer = mifareTag.readBlock(mifareTag.sectorToBlock(sectorIndex)+i);
492
- appendBytesToRnArray(result, buffer);
493
- }
494
-
495
- callback.invoke(null, result);
496
- } catch (TagLostException ex) {
497
- callback.invoke("mifareClassicReadSector fail: TAG_LOST");
498
- } catch (Exception ex) {
499
- callback.invoke("mifareClassicReadSector fail: " + ex);
500
- }
501
- } else {
502
- callback.invoke(ERR_NO_TECH_REQ);
503
- }
243
+ MifareClassicHandler.readSector(
244
+ techRequest,
245
+ (int)_sectorIndex,
246
+ callback
247
+ );
504
248
  }
505
249
  }
506
250
 
507
251
  @ReactMethod
508
252
  public void mifareClassicWriteBlock(double _blockIndex, ReadableArray block, Callback callback) {
509
- int blockIndex = (int)_blockIndex;
510
253
  synchronized(this) {
511
- if (techRequest != null) {
512
- try {
513
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
514
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
515
- // Not a mifare card, fail
516
- callback.invoke("mifareClassicWriteBlock fail: TYPE_UNKNOWN");
517
- return;
518
- } else if (blockIndex >= mifareTag.getBlockCount()) {
519
- // Check if in range
520
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicWriteBlock fail: invalid block %d (max %d)", blockIndex, mifareTag.getBlockCount());
521
- callback.invoke(msg);
522
- return;
523
- } else if (block.size() != MifareClassic.BLOCK_SIZE) {
524
- // Wrong block count
525
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicWriteBlock fail: invalid block size %d (should be %d)", block.size(), MifareClassic.BLOCK_SIZE);
526
- callback.invoke(msg);
527
- return;
528
- }
529
-
530
- byte[] buffer = rnArrayToBytes(block);
531
- mifareTag.writeBlock(blockIndex, buffer);
532
-
533
- callback.invoke(null, true);
534
- } catch (TagLostException ex) {
535
- callback.invoke("mifareClassicWriteBlock fail: TAG_LOST");
536
- } catch (Exception ex) {
537
- callback.invoke("mifareClassicWriteBlock fail: " + ex);
538
- }
539
- } else {
540
- callback.invoke(ERR_NO_TECH_REQ);
541
- }
254
+ MifareClassicHandler.writeBlock(
255
+ techRequest,
256
+ (int)_blockIndex,
257
+ block,
258
+ callback
259
+ );
542
260
  }
543
261
  }
544
262
 
545
263
  @ReactMethod
546
264
  public void mifareClassicIncrementBlock(double _blockIndex, double _value, Callback callback) {
547
- int blockIndex = (int)_blockIndex;
548
- int value = (int)_value;
549
265
  synchronized(this) {
550
- if (techRequest != null) {
551
- try {
552
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
553
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
554
- // Not a mifare card, fail
555
- callback.invoke("mifareClassicIncrementBlock fail: TYPE_UNKNOWN");
556
- return;
557
- } else if (blockIndex >= mifareTag.getBlockCount()) {
558
- // Check if in range
559
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicIncrementBlock fail: invalid block %d (max %d)", blockIndex, mifareTag.getBlockCount());
560
- callback.invoke(msg);
561
- return;
562
- }
563
-
564
- mifareTag.increment(blockIndex, value);
565
-
566
- callback.invoke(null, true);
567
- } catch (TagLostException ex) {
568
- callback.invoke("mifareClassicIncrementBlock fail: TAG_LOST");
569
- } catch (Exception ex) {
570
- callback.invoke("mifareClassicIncrementBlock fail: " + ex);
571
- }
572
- } else {
573
- callback.invoke(ERR_NO_TECH_REQ);
574
- }
266
+ MifareClassicHandler.incrementBlock(
267
+ techRequest,
268
+ (int)_blockIndex,
269
+ (int)_value,
270
+ callback
271
+ );
575
272
  }
576
273
  }
577
274
 
578
275
  @ReactMethod
579
276
  public void mifareClassicDecrementBlock(double _blockIndex, double _value, Callback callback) {
580
- int blockIndex = (int)_blockIndex;
581
- int value = (int)_value;
582
277
  synchronized(this) {
583
- if (techRequest != null) {
584
- try {
585
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
586
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
587
- // Not a mifare card, fail
588
- callback.invoke("mifareClassicDecrementBlock fail: TYPE_UNKNOWN");
589
- return;
590
- } else if (blockIndex >= mifareTag.getBlockCount()) {
591
- // Check if in range
592
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicDecrementBlock fail: invalid block %d (max %d)", blockIndex, mifareTag.getBlockCount());
593
- callback.invoke(msg);
594
- return;
595
- }
596
-
597
- mifareTag.decrement(blockIndex, value);
598
-
599
- callback.invoke(null, true);
600
- } catch (TagLostException ex) {
601
- callback.invoke("mifareClassicDecrementBlock fail: TAG_LOST");
602
- } catch (Exception ex) {
603
- callback.invoke("mifareClassicDecrementBlock fail: " + ex);
604
- }
605
- } else {
606
- callback.invoke(ERR_NO_TECH_REQ);
607
- }
278
+ MifareClassicHandler.decrementBlock(
279
+ techRequest,
280
+ (int)_blockIndex,
281
+ (int)_value,
282
+ callback
283
+ );
608
284
  }
609
285
  }
610
286
 
611
287
  @ReactMethod
612
288
  public void mifareClassicTransferBlock(double _blockIndex, Callback callback) {
613
- int blockIndex = (int)_blockIndex;
614
289
  synchronized(this) {
615
- if (techRequest != null) {
616
- try {
617
- MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
618
- if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
619
- // Not a mifare card, fail
620
- callback.invoke("mifareClassicTransferBlock fail: TYPE_UNKNOWN");
621
- return;
622
- } else if (blockIndex >= mifareTag.getBlockCount()) {
623
- // Check if in range
624
- @SuppressLint("DefaultLocale") String msg = String.format("mifareClassicTransferBlock fail: invalid block %d (max %d)", blockIndex, mifareTag.getBlockCount());
625
- callback.invoke(msg);
626
- return;
627
- }
628
-
629
- mifareTag.transfer(blockIndex);
630
-
631
- callback.invoke(null, true);
632
- } catch (TagLostException ex) {
633
- callback.invoke("mifareClassicTransferBlock fail: TAG_LOST");
634
- } catch (Exception ex) {
635
- callback.invoke("mifareClassicTransferBlock fail: " + ex);
636
- }
637
- } else {
638
- callback.invoke(ERR_NO_TECH_REQ);
639
- }
290
+ MifareClassicHandler.transferBlock(
291
+ techRequest,
292
+ (int)_blockIndex,
293
+ callback
294
+ );
640
295
  }
641
296
  }
642
297
 
643
298
  @ReactMethod
644
299
  public void mifareUltralightReadPages(double pageOffset, Callback callback) {
645
300
  synchronized(this) {
646
- if (techRequest != null) {
647
- try {
648
- MifareUltralight techHandle = (MifareUltralight)techRequest.getTechHandle();
649
- byte[] resultBytes = techHandle.readPages((int)pageOffset);
650
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
651
- callback.invoke(null, resultRnArray);
652
- } catch (TagLostException ex) {
653
- callback.invoke("mifareUltralight fail: TAG_LOST");
654
- } catch (Exception ex) {
655
- callback.invoke("mifareUltralight fail: " + ex);
656
- }
657
- } else {
658
- callback.invoke(ERR_NO_TECH_REQ);
659
- }
301
+ MifareUltralightHandler.readPages(
302
+ techRequest,
303
+ (int)pageOffset,
304
+ callback
305
+ );
660
306
  }
661
307
  }
662
308
 
663
309
  @ReactMethod
664
310
  public void mifareUltralightWritePage(double pageOffset, ReadableArray rnArray, Callback callback) {
665
311
  synchronized(this) {
666
- if (techRequest != null) {
667
- try {
668
- byte[] bytes = rnArrayToBytes(rnArray);
669
- MifareUltralight techHandle = (MifareUltralight)techRequest.getTechHandle();
670
- techHandle.writePage((int)pageOffset, bytes);
671
- callback.invoke();
672
- } catch (TagLostException ex) {
673
- callback.invoke("mifareUltralight fail: TAG_LOST");
674
- } catch (Exception ex) {
675
- callback.invoke("mifareUltralight fail: " + ex);
676
- }
677
- } else {
678
- callback.invoke(ERR_NO_TECH_REQ);
679
- }
312
+ MifareUltralightHandler.writePage(
313
+ techRequest,
314
+ (int)pageOffset,
315
+ rnArray,
316
+ callback
317
+ );
680
318
  }
681
319
  }
682
320
 
683
321
  @ReactMethod
684
322
  public void makeReadOnly(Callback callback) {
685
323
  synchronized(this) {
686
- if (techRequest != null) {
687
- try {
688
- Ndef ndef = (Ndef)techRequest.getTechHandle();
689
- boolean result = ndef.makeReadOnly();
690
- callback.invoke(null, result);
691
- } catch (Exception ex) {
692
- Log.d(LOG_TAG, ex.toString());
693
- callback.invoke(ex.toString());
694
- }
695
- } else {
696
- callback.invoke(ERR_NO_TECH_REQ);
697
- }
324
+ NdefHandler.makeReadOnly(techRequest, callback);
698
325
  }
699
326
  }
700
327
 
701
- @Override
702
- public void setAlertMessage(String message, Callback callback) {
703
-
704
- }
705
-
706
- @Override
707
- public void isSessionAvailable(Callback callback) {
708
-
709
- }
710
-
711
- @Override
712
- public void isTagSessionAvailable(Callback callback) {
713
-
714
- }
715
-
716
- @Override
717
- public void sendMifareCommand(ReadableArray bytes, Callback callback) {
718
-
719
- }
720
-
721
- @Override
722
- public void sendCommandAPDU(ReadableMap payload, Callback callback) {
723
-
724
- }
725
-
726
- @Override
727
- public void sendCommandAPDUBytes(ReadableArray bytes, Callback callback) {
728
-
729
- }
730
-
731
- @Override
732
- public void sendFelicaCommand(ReadableArray bytes, Callback callback) {
733
-
734
- }
735
-
736
328
  @ReactMethod
737
329
  public void setTimeout(double timeout, Callback callback) {
738
330
  synchronized (this) {
739
- if (techRequest != null) {
740
- try {
741
- String tech = techRequest.getTechType();
742
- TagTechnology baseTechHandle = techRequest.getTechHandle();
743
- // TagTechnology is the base class for each tech (ex, NfcA, NfcB, IsoDep ...)
744
- // but it doesn't provide transceive in its interface, so we need to explicitly cast it
745
- switch (tech) {
746
- case "NfcA": {
747
- NfcA techHandle = (NfcA) baseTechHandle;
748
- techHandle.setTimeout((int)timeout);
749
- callback.invoke();
750
- return;
751
- }
752
- case "NfcF": {
753
- NfcF techHandle = (NfcF) baseTechHandle;
754
- techHandle.setTimeout((int)timeout);
755
- callback.invoke();
756
- return;
757
- }
758
- case "IsoDep": {
759
- IsoDep techHandle = (IsoDep) baseTechHandle;
760
- techHandle.setTimeout((int)timeout);
761
- callback.invoke();
762
- return;
763
- }
764
- case "MifareClassic": {
765
- MifareClassic techHandle = (MifareClassic) baseTechHandle;
766
- techHandle.setTimeout((int)timeout);
767
- callback.invoke();
768
- return;
769
- }
770
- case "MifareUltralight": {
771
- MifareUltralight techHandle = (MifareUltralight) baseTechHandle;
772
- techHandle.setTimeout((int)timeout);
773
- callback.invoke();
774
- return;
775
- }
776
- }
777
- Log.d(LOG_TAG, "setTimeout not supported");
778
- callback.invoke(ERR_API_NOT_SUPPORT);
779
- } catch (Exception ex) {
780
- Log.d(LOG_TAG, ex.toString());
781
- callback.invoke(ex.toString());
782
- }
783
- } else {
784
- callback.invoke(ERR_NO_TECH_REQ);
785
- }
331
+ NfcTechIoRouter.setTimeout(
332
+ techRequest,
333
+ (int)timeout,
334
+ callback
335
+ );
786
336
  }
787
337
  }
788
338
 
789
339
  @ReactMethod
790
340
  public void getTimeout(Callback callback) {
791
341
  synchronized (this) {
792
- if (techRequest != null) {
793
- try {
794
- String tech = techRequest.getTechType();
795
- TagTechnology baseTechHandle = techRequest.getTechHandle();
796
- // TagTechnology is the base class for each tech (ex, NfcA, NfcB, IsoDep ...)
797
- // but it doesn't provide transceive in its interface, so we need to explicitly cast it
798
- switch (tech) {
799
- case "NfcA": {
800
- NfcA techHandle = (NfcA) baseTechHandle;
801
- int timeout = techHandle.getTimeout();
802
- callback.invoke(null, timeout);
803
- return;
804
- }
805
- case "NfcF": {
806
- NfcF techHandle = (NfcF) baseTechHandle;
807
- int timeout = techHandle.getTimeout();
808
- callback.invoke(null, timeout);
809
- return;
810
- }
811
- case "IsoDep": {
812
- IsoDep techHandle = (IsoDep) baseTechHandle;
813
- int timeout = techHandle.getTimeout();
814
- callback.invoke(null, timeout);
815
- return;
816
- }
817
- case "MifareClassic": {
818
- MifareClassic techHandle = (MifareClassic) baseTechHandle;
819
- int timeout = techHandle.getTimeout();
820
- callback.invoke(null, timeout);
821
- return;
822
- }
823
- case "MifareUltralight": {
824
- MifareUltralight techHandle = (MifareUltralight) baseTechHandle;
825
- int timeout = techHandle.getTimeout();
826
- callback.invoke(null, timeout);
827
- return;
828
- }
829
- }
830
- Log.d(LOG_TAG, "getTimeout not supported");
831
- callback.invoke(ERR_API_NOT_SUPPORT);
832
- } catch (Exception ex) {
833
- Log.d(LOG_TAG, ex.toString());
834
- callback.invoke(ex.toString());
835
- }
836
- } else {
837
- callback.invoke(ERR_NO_TECH_REQ);
838
- }
342
+ NfcTechIoRouter.getTimeout(techRequest, callback);
839
343
  }
840
344
  }
841
345
 
842
346
  @ReactMethod
843
347
  public void connect(ReadableArray techs, Callback callback){
844
348
  synchronized(this) {
349
+ if (hasPendingRequest()) {
350
+ callback.invoke(ERR_MULTI_REQ);
351
+ return;
352
+ }
353
+
354
+ TagTechnologyRequest request = new TagTechnologyRequest(techs.toArrayList(), null);
845
355
  try {
846
- techRequest = new TagTechnologyRequest(techs.toArrayList(), null);
847
- techRequest.connect(this.tag);
848
- 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;
849
362
  } catch (Exception ex) {
850
363
  callback.invoke(ex.toString());
364
+ return;
851
365
  }
366
+ callback.invoke(null, null);
852
367
  }
853
368
  }
854
369
 
855
370
  @ReactMethod
856
371
  public void close(Callback callback){
857
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();
858
380
  try {
859
- techRequest.close();
860
- callback.invoke(null, null);
861
- } catch (Exception ex) {
862
- 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);
863
384
  }
385
+ callback.invoke(null, null);
864
386
  }
865
387
  }
866
388
 
867
389
  @ReactMethod
868
390
  public void transceive(ReadableArray rnArray, Callback callback) {
869
391
  synchronized(this) {
870
- if (techRequest != null) {
871
- try {
872
- String tech = techRequest.getTechType();
873
- byte[] bytes = rnArrayToBytes(rnArray);
874
-
875
- TagTechnology baseTechHandle = techRequest.getTechHandle();
876
- // TagTechnology is the base class for each tech (ex, NfcA, NfcB, IsoDep ...)
877
- // but it doesn't provide transceive in its interface, so we need to explicitly cast it
878
- switch (tech) {
879
- case "NfcA": {
880
- NfcA techHandle = (NfcA) baseTechHandle;
881
- byte[] resultBytes = techHandle.transceive(bytes);
882
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
883
- callback.invoke(null, resultRnArray);
884
- return;
885
- }
886
- case "NfcB": {
887
- NfcB techHandle = (NfcB) baseTechHandle;
888
- byte[] resultBytes = techHandle.transceive(bytes);
889
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
890
- callback.invoke(null, resultRnArray);
891
- return;
892
- }
893
- case "NfcF": {
894
- NfcF techHandle = (NfcF) baseTechHandle;
895
- byte[] resultBytes = techHandle.transceive(bytes);
896
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
897
- callback.invoke(null, resultRnArray);
898
- return;
899
- }
900
- case "NfcV": {
901
- NfcV techHandle = (NfcV) baseTechHandle;
902
- byte[] resultBytes = techHandle.transceive(bytes);
903
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
904
- callback.invoke(null, resultRnArray);
905
- return;
906
- }
907
- case "IsoDep": {
908
- IsoDep techHandle = (IsoDep) baseTechHandle;
909
- byte[] resultBytes = techHandle.transceive(bytes);
910
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
911
- callback.invoke(null, resultRnArray);
912
- return;
913
- }
914
- case "MifareClassic": {
915
- MifareClassic techHandle = (MifareClassic) baseTechHandle;
916
- byte[] resultBytes = techHandle.transceive(bytes);
917
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
918
- callback.invoke(null, resultRnArray);
919
- return;
920
- }
921
- case "MifareUltralight": {
922
- MifareUltralight techHandle = (MifareUltralight) baseTechHandle;
923
- byte[] resultBytes = techHandle.transceive(bytes);
924
- WritableArray resultRnArray = bytesToRnArray(resultBytes);
925
- callback.invoke(null, resultRnArray);
926
- return;
927
- }
928
- }
929
- Log.d(LOG_TAG, "transceive not supported");
930
- callback.invoke(ERR_API_NOT_SUPPORT);
931
- } catch (Exception ex) {
932
- Log.d(LOG_TAG, "transceive fail: " + ex);
933
- callback.invoke(ERR_TRANSCEIVE_FAIL);
934
- }
935
- } else {
936
- callback.invoke(ERR_NO_TECH_REQ);
937
- }
392
+ NfcTechIoRouter.transceive(
393
+ techRequest,
394
+ rnArray,
395
+ callback
396
+ );
938
397
  }
939
398
  }
940
399
 
941
400
  @ReactMethod
942
401
  public void getMaxTransceiveLength(Callback callback) {
943
402
  synchronized(this) {
944
- if (techRequest != null) {
945
- try {
946
- String tech = techRequest.getTechType();
947
-
948
- TagTechnology baseTechHandle = techRequest.getTechHandle();
949
- // TagTechnology is the base class for each tech (ex, NfcA, NfcB, IsoDep ...)
950
- // but it doesn't provide transceive in its interface, so we need to explicitly cast it
951
- switch (tech) {
952
- case "NfcA": {
953
- NfcA techHandle = (NfcA) baseTechHandle;
954
- int max = techHandle.getMaxTransceiveLength();
955
- callback.invoke(null, max);
956
- return;
957
- }
958
- case "NfcB": {
959
- NfcB techHandle = (NfcB) baseTechHandle;
960
- int max = techHandle.getMaxTransceiveLength();
961
- callback.invoke(null, max);
962
- return;
963
- }
964
- case "NfcF": {
965
- NfcF techHandle = (NfcF) baseTechHandle;
966
- int max = techHandle.getMaxTransceiveLength();
967
- callback.invoke(null, max);
968
- return;
969
- }
970
- case "NfcV": {
971
- NfcV techHandle = (NfcV) baseTechHandle;
972
- int max = techHandle.getMaxTransceiveLength();
973
- callback.invoke(null, max);
974
- return;
975
- }
976
- case "IsoDep": {
977
- IsoDep techHandle = (IsoDep) baseTechHandle;
978
- int max = techHandle.getMaxTransceiveLength();
979
- callback.invoke(null, max);
980
- return;
981
- }
982
- case "MifareUltralight": {
983
- MifareUltralight techHandle = (MifareUltralight) baseTechHandle;
984
- int max = techHandle.getMaxTransceiveLength();
985
- callback.invoke(null, max);
986
- return;
987
- }
988
- }
989
- Log.d(LOG_TAG, "getMaxTransceiveLength not supported");
990
- callback.invoke(ERR_API_NOT_SUPPORT);
991
- } catch (Exception ex) {
992
- Log.d(LOG_TAG, "getMaxTransceiveLength fail");
993
- callback.invoke(ex.toString());
994
- }
995
- } else {
996
- callback.invoke(ERR_NO_TECH_REQ);
997
- }
403
+ NfcTechIoRouter.getMaxTransceiveLength(techRequest, callback);
998
404
  }
999
405
  }
1000
406
 
1001
407
  @ReactMethod
1002
408
  public void cancelNdefWrite(Callback callback) {
1003
409
  synchronized(this) {
1004
- if (writeNdefRequest != null) {
1005
- writeNdefRequest.callback.invoke(ERR_CANCEL);
1006
- writeNdefRequest = null;
1007
- callback.invoke();
1008
- } else {
1009
- callback.invoke(ERR_NOT_REGISTERED);
1010
- }
410
+ writeNdefRequest = NdefHandler.cancelNdefWrite(writeNdefRequest, callback);
1011
411
  }
1012
412
  }
1013
413
 
1014
414
  @ReactMethod
1015
415
  public void requestNdefWrite(ReadableArray rnArray, ReadableMap options, Callback callback) {
1016
416
  synchronized(this) {
1017
- if (!isForegroundEnabled) {
1018
- callback.invoke(ERR_NOT_REGISTERED);
1019
- return;
1020
- }
1021
-
1022
- if (hasPendingRequest()) {
1023
- callback.invoke(ERR_MULTI_REQ);
1024
- } else {
1025
- boolean format = options.getBoolean("format");
1026
- boolean formatReadOnly = options.getBoolean("formatReadOnly");
1027
-
1028
- try {
1029
- NdefMessage msgToWrite;
1030
-
1031
- /// the only case we allow ndef message to be null is when formatting, see:
1032
- /// https://developer.android.com/reference/android/nfc/tech/NdefFormatable.html#format(android.nfc.NdefMessage)
1033
- /// this API allows the `firstMessage` to be null
1034
- if (format && rnArray == null) {
1035
- msgToWrite = null;
1036
- } else {
1037
- byte[] bytes = rnArrayToBytes(rnArray);
1038
- msgToWrite = new NdefMessage(bytes);
1039
- }
1040
-
1041
- writeNdefRequest = new WriteNdefRequest(
1042
- msgToWrite,
1043
- callback, // defer the callback
1044
- format,
1045
- formatReadOnly
1046
- );
1047
- } catch (FormatException e) {
1048
- callback.invoke(e.toString());
1049
- }
1050
- }
417
+ writeNdefRequest = NdefHandler.requestNdefWrite(
418
+ rnArray,
419
+ options,
420
+ isForegroundEnabled,
421
+ hasPendingRequest(),
422
+ writeNdefRequest,
423
+ callback
424
+ );
1051
425
  }
1052
426
  }
1053
427
 
1054
428
  @ReactMethod
1055
429
  public void start(Callback callback) {
1056
- var context = getReactApplicationContext();
1057
- NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(context);
1058
- if (nfcAdapter != null) {
1059
- 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
+ }
1060
438
 
1061
- IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
439
+ Log.d(LOG_TAG, "start");
1062
440
  Activity currentActivity = context.getCurrentActivity();
1063
441
  if (currentActivity == null) {
1064
442
  callback.invoke(ERR_GET_ACTIVITY_FAIL);
1065
443
  return;
1066
444
  }
1067
445
 
1068
- currentActivity.registerReceiver(mReceiver, filter);
1069
- Intent launchIntent = currentActivity.getIntent();
1070
- // we consider the launching intent to be background
1071
- 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
+ }
1072
459
  callback.invoke();
1073
- } else {
1074
- Log.d(LOG_TAG, "not support in this device");
1075
- callback.invoke(ERR_NO_NFC_SUPPORT);
1076
460
  }
1077
461
  }
1078
462
 
@@ -1094,7 +478,7 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
1094
478
  // compatible with MifareClassic
1095
479
  // TODO: Check if it's the same case with MifareUltralight
1096
480
  if (tech.equals("MifareClassic")) {
1097
- if (!MifareUtil.isDeviceSupported(currentActivity)) {
481
+ if (!Util.isDeviceSupported(currentActivity)) {
1098
482
  callback.invoke(null, false);
1099
483
  return;
1100
484
  }
@@ -1155,66 +539,47 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
1155
539
  callback.invoke();
1156
540
  }
1157
541
 
1158
- @Override
1159
- public void restartTechnologyRequest(Callback callback) {
1160
-
1161
- }
1162
-
1163
- @Override
1164
- public void invalidateSession(Callback callback) {
1165
-
1166
- }
1167
-
1168
- @Override
1169
- public void invalidateSessionWithError(String message, Callback callback) {
1170
-
1171
- }
1172
-
1173
542
  @ReactMethod
1174
543
  public void registerTagEvent(ReadableMap options, Callback callback) {
1175
- isReaderModeEnabled = options.getBoolean("isReaderModeEnabled");
1176
- readerModeFlags = options.getInt("readerModeFlags");
1177
- readerModeDelay = options.getInt("readerModeDelay");
1178
-
1179
- Log.d(LOG_TAG, "registerTagEvent");
1180
- isForegroundEnabled = true;
1181
-
1182
- // capture all mime-based dispatch NDEF
1183
- IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
1184
- try {
1185
- ndef.addDataType("*/*");
1186
- } catch (MalformedMimeTypeException e) {
1187
- throw new RuntimeException("fail", e);
1188
- }
1189
- 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
+ }
1190
554
 
1191
- // capture all rest NDEF, such as uri-based
1192
- intentFilters.add(new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED));
1193
- 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));
1194
563
 
1195
- // for those without NDEF, get them as tags
1196
- 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;
1197
568
 
1198
- if (isResumed) {
1199
- enableDisableForegroundDispatch(true);
569
+ if (isResumed) {
570
+ enableDisableForegroundDispatch(true);
571
+ }
572
+ callback.invoke();
1200
573
  }
1201
- callback.invoke();
1202
574
  }
1203
575
 
1204
576
  @ReactMethod
1205
577
  public void unregisterTagEvent(Callback callback) {
1206
- Log.d(LOG_TAG, "unregisterTagEvent");
1207
- if (isResumed) {
1208
- enableDisableForegroundDispatch(false);
578
+ synchronized(this) {
579
+ Log.d(LOG_TAG, "unregisterTagEvent");
580
+ resetTagRegistration();
581
+ callback.invoke();
1209
582
  }
1210
-
1211
- intentFilters.clear();
1212
- isForegroundEnabled = false;
1213
- isReaderModeEnabled = false;
1214
- readerModeFlags = 0;
1215
- readerModeDelay = 0;
1216
-
1217
- callback.invoke();
1218
583
  }
1219
584
 
1220
585
  @ReactMethod
@@ -1234,124 +599,121 @@ class NfcManager extends NativeNfcManagerSpec implements ActivityEventListener,
1234
599
  }
1235
600
 
1236
601
  @Override
1237
- public void iso15693_getSystemInfo(double requestFlag, Callback callback) {
1238
-
1239
- }
1240
-
1241
- @Override
1242
- public void iso15693_readSingleBlock(ReadableMap options, Callback callback) {
1243
-
1244
- }
1245
-
1246
- @Override
1247
- public void iso15693_readMultipleBlocks(ReadableMap options, Callback callback) {
1248
-
1249
- }
1250
-
1251
- @Override
1252
- public void iso15693_writeSingleBlock(ReadableMap options, Callback callback) {
1253
-
1254
- }
1255
-
1256
- @Override
1257
- public void iso15693_lockBlock(ReadableMap options, Callback callback) {
1258
-
1259
- }
1260
-
1261
- @Override
1262
- public void iso15693_writeAFI(ReadableMap options, Callback callback) {
1263
-
1264
- }
1265
-
1266
- @Override
1267
- public void iso15693_lockAFI(ReadableMap options, Callback callback) {
1268
-
1269
- }
1270
-
1271
- @Override
1272
- public void iso15693_writeDSFID(ReadableMap options, Callback callback) {
1273
-
602
+ public void onHostResume() {
603
+ Log.d(LOG_TAG, "onResume");
604
+ isResumed = true;
605
+ if (isForegroundEnabled) {
606
+ enableDisableForegroundDispatch(true);
607
+ }
1274
608
  }
1275
609
 
1276
610
  @Override
1277
- public void iso15693_lockDSFID(ReadableMap options, Callback callback) {
1278
-
611
+ public void onHostPause() {
612
+ Log.d(LOG_TAG, "onPause");
613
+ isResumed = false;
614
+ enableDisableForegroundDispatch(false);
1279
615
  }
1280
616
 
1281
617
  @Override
1282
- public void iso15693_resetToReady(ReadableMap options, Callback callback) {
1283
-
618
+ public void onHostDestroy() {
619
+ Log.d(LOG_TAG, "onDestroy");
620
+ cleanUpNativeState();
1284
621
  }
1285
622
 
1286
623
  @Override
1287
- public void iso15693_select(ReadableMap options, Callback callback) {
1288
-
624
+ public void invalidate() {
625
+ cleanUpNativeState();
626
+ ReactApplicationContext context = getReactApplicationContext();
627
+ context.removeActivityEventListener(this);
628
+ context.removeLifecycleEventListener(this);
629
+ super.invalidate();
1289
630
  }
1290
631
 
1291
632
  @Override
1292
- public void iso15693_stayQuiet(ReadableMap options, Callback callback) {
1293
-
1294
- }
1295
-
1296
- @Override
1297
- public void iso15693_customCommand(ReadableMap options, Callback callback) {
1298
-
633
+ public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
634
+ Log.d(LOG_TAG, "onActivityResult");
1299
635
  }
1300
636
 
1301
637
  @Override
1302
- public void iso15693_sendRequest(ReadableMap options, Callback callback) {
1303
-
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
+ }
1304
649
  }
1305
650
 
1306
- @Override
1307
- public void iso15693_extendedReadSingleBlock(ReadableMap options, Callback callback) {
1308
-
651
+ private boolean hasPendingRequest() {
652
+ return writeNdefRequest != null || techRequest != null;
1309
653
  }
1310
654
 
1311
- @Override
1312
- public void iso15693_extendedReadMultipleBlocks(ReadableMap options, Callback callback) {
1313
-
655
+ private TagTechnologyRequest detachTechnologyRequest() {
656
+ TagTechnologyRequest request = techRequest;
657
+ techRequest = null;
658
+ return request;
1314
659
  }
1315
660
 
1316
- @Override
1317
- public void iso15693_extendedWriteSingleBlock(ReadableMap options, Callback callback) {
1318
-
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;
1319
671
  }
1320
672
 
1321
- @Override
1322
- public void iso15693_extendedLockBlock(ReadableMap options, Callback callback) {
673
+ private void cleanUpNativeState() {
674
+ synchronized(this) {
675
+ resetTagRegistration();
676
+ isResumed = false;
1323
677
 
1324
- }
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
+ }
1325
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
+ }
1326
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
+ }
1327
706
 
1328
- @Override
1329
- public void onHostResume() {
1330
- Log.d(LOG_TAG, "onResume");
1331
- isResumed = true;
1332
- if (isForegroundEnabled) {
1333
- enableDisableForegroundDispatch(true);
707
+ tag = null;
708
+ bgTag = null;
1334
709
  }
1335
710
  }
1336
711
 
1337
- @Override
1338
- public void onHostPause() {
1339
- Log.d(LOG_TAG, "onPause");
1340
- isResumed = false;
1341
- enableDisableForegroundDispatch(false);
1342
- }
1343
-
1344
- @Override
1345
- public void onHostDestroy() {
1346
- Log.d(LOG_TAG, "onDestroy");
1347
- }
1348
-
1349
712
  private void enableDisableForegroundDispatch(boolean enable) {
1350
713
  Log.i(LOG_TAG, "enableForegroundDispatch, enable = " + enable);
1351
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,6 +739,31 @@ 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
768
  Activity activity = getReactApplicationContext().getCurrentActivity();
1411
769
  assert activity != null;
@@ -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 != null && 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
-