react-native-nfc-manager 4.0.0-beta.0 → 4.0.0-beta.10

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