2020
2121import com .facebook .react .ReactApplication ;
2222import com .facebook .react .ReactHost ;
23- import com .facebook .react .ReactInstanceEventListener ;
2423import com .facebook .react .bridge .Arguments ;
2524import com .facebook .react .bridge .ReactContext ;
2625import com .facebook .react .bridge .UiThreadUtil ;
2726import com .facebook .react .jstasks .HeadlessJsTaskConfig ;
2827import com .facebook .react .jstasks .HeadlessJsTaskContext ;
2928import com .facebook .react .jstasks .HeadlessJsTaskEventListener ;
3029
30+ import java .util .HashMap ;
3131import java .util .List ;
3232import java .util .Locale ;
3333import java .util .UUID ;
3434
3535@ RequiresApi (api = Build .VERSION_CODES .TIRAMISU )
36- public class HCEService extends HostApduService implements ReactInstanceEventListener , HCEServiceCallback {
36+ public class HCEService extends HostApduService implements HCEServiceCallback {
3737 private static final String TAG = "HCEService" ;
3838
3939 private boolean isForeground ;
4040 private String backgroundSessionUUID ;
4141 private RTNHCEAndroidModule hceModule ;
4242 private byte [] pendingCAPDU ;
4343 private volatile boolean needsResponse ;
44+ private final HashMap <String , Integer > taskSessionIdMap ;
45+
46+ public HCEService () {
47+ super ();
48+
49+ taskSessionIdMap = new HashMap <>();
50+ }
4451
4552 private boolean isAppOnForeground (Context context ) {
4653 /*
@@ -67,6 +74,7 @@ private boolean isAppOnForeground(Context context) {
6774 @ Override
6875 public void onBackgroundHCEInit (String handle ) {
6976 Log .d (TAG , "HCEService:onBackgroundHCEInit" );
77+ Log .d (TAG , "HCEService:onBackgroundHCEInit:" + handle + ":" + backgroundSessionUUID );
7078
7179 if (handle == null && backgroundSessionUUID != null ) {
7280 Log .d (TAG , "HCEService:onBackgroundHCEInit foreground call to background session" );
@@ -83,6 +91,35 @@ public void onBackgroundHCEInit(String handle) {
8391 }
8492 }
8593
94+ @ Override
95+ public void onBackgroundHCEFinish (String handle ) {
96+ Log .d (TAG , "HCEService:onBackgroundHCEFinish" );
97+ Integer taskId = taskSessionIdMap .get (handle );
98+
99+ if (taskId == null ) {
100+ Log .d (TAG , "HCEService:onBackgroundHCEFinish unable to resolve taskId" );
101+ throw new IllegalArgumentException ();
102+ }
103+
104+ ReactHost reactHost = ((ReactApplication ) getApplication ()).getReactHost ();
105+
106+ if (reactHost == null ) {
107+ Log .d (TAG , "HCEService:onBackgroundHCEFinish getReactHost() returned null" );
108+ throw new IllegalArgumentException ();
109+ }
110+
111+ ReactContext reactContext = reactHost .getCurrentReactContext ();
112+
113+ if (reactContext == null ) {
114+ Log .d (TAG , "HCEService:onBackgroundHCEFinish getCurrentReactContext() returned null" );
115+ throw new IllegalArgumentException ();
116+ }
117+
118+ HeadlessJsTaskContext headlessJsTaskContext = Companion .getInstance (reactContext );
119+ headlessJsTaskContext .finishTask (taskId );
120+ taskSessionIdMap .remove (handle );
121+ }
122+
86123 @ Override
87124 public void onRespondAPDU (String handle , String rapdu ) {
88125 Log .d (TAG , "HCEService:onRespondAPDU" );
@@ -110,13 +147,13 @@ public byte[] processCommandApdu(byte[] command, Bundle extras) {
110147 String capdu = BinaryUtils .ByteArrayToHexString (command ).toUpperCase (Locale .ROOT );
111148
112149 if (isForeground ) {
113- if (hceModule ._isHCERunning () && ! hceModule .isHCEBrokenConnection ()) {
150+ if (hceModule ._isHCERunning () && hceModule .isHCEActiveConnection ()) {
114151 Log .d (TAG , "HCEService:processCommandApdu foreground sendEvent received" );
115152 needsResponse = true ;
116153 hceModule .sendEvent ("received" , capdu );
117154 } else {
118155 Log .d (TAG , "HCEService:processCommandApdu foreground respond 6999" );
119- return new byte [] { (byte ) 0x69 , (byte ) 0x99 };
156+ return new byte []{ (byte ) 0x69 , (byte ) 0x99 };
120157 }
121158 } else {
122159 if (hceModule != null && hceModule .isHCEBackgroundHandlerReady ()) {
@@ -174,13 +211,29 @@ public void onCreate() {
174211 } else {
175212 ReactContext reactContext = reactHost .getCurrentReactContext ();
176213 Log .d (TAG , "HCEService:onCreate background" );
177- this .backgroundSessionUUID = UUID .randomUUID ().toString ();
214+ final String useSessID = UUID .randomUUID ().toString ();
215+ backgroundSessionUUID = useSessID ;
178216
179217 if (reactContext == null ) {
180- reactHost .addReactInstanceEventListener (this );
218+ reactHost .addReactInstanceEventListener (evReactContext -> {
219+ HeadlessJsTaskContext headlessJsTaskContext = Companion .getInstance (evReactContext );
220+ headlessJsTaskContext .addTaskEventListener (new HeadlessJsTaskEventListener () {
221+ @ Override
222+ public void onHeadlessJsTaskStart (int i ) {
223+ Log .d (TAG , "HCEService:HeadlessJsTaskEventListener:onHeadlessJsTaskStart: " + i );
224+ }
225+
226+ @ Override
227+ public void onHeadlessJsTaskFinish (int i ) {
228+ Log .d (TAG , "HCEService:HeadlessJsTaskEventListener:onHeadlessJsTaskFinish: " + i );
229+ }
230+ });
231+
232+ setupRunJSTask (evReactContext , useSessID );
233+ });
181234 reactHost .start ();
182235 } else {
183- setupRunJSTask (reactContext );
236+ setupRunJSTask (reactContext , useSessID );
184237 }
185238 }
186239 }
@@ -191,37 +244,20 @@ public void onDeactivated(int reason) {
191244 needsResponse = false ;
192245
193246 if (isForeground ) {
194- if (this .hceModule != null && ! this .hceModule .isHCEBrokenConnection ()) {
247+ if (this .hceModule != null && this .hceModule .isHCEActiveConnection ()) {
195248 this .hceModule .sendEvent ("readerDeselected" , "" );
196249 }
197- } else {
198- this . hceModule . sendBackgroundEvent ( backgroundSessionUUID , "readerDeselected" , "" ) ;
199- }
250+ } else if ( backgroundSessionUUID != null ) {
251+ String prevBackgroundSessionUUID = backgroundSessionUUID ;
252+ backgroundSessionUUID = null ;
200253
201- if (this .hceModule != null ) {
202- this .hceModule .setHCEService (null );
203- }
204- }
205-
206- @ Override
207- public void onReactContextInitialized (@ NonNull ReactContext reactContext ) {
208- HeadlessJsTaskContext headlessJsTaskContext = Companion .getInstance (reactContext );
209- headlessJsTaskContext .addTaskEventListener (new HeadlessJsTaskEventListener () {
210- @ Override
211- public void onHeadlessJsTaskStart (int i ) {
212- Log .d (TAG , "HCEService:HeadlessJsTaskEventListener:onHeadlessJsTaskStart: " + i );
213- }
214-
215- @ Override
216- public void onHeadlessJsTaskFinish (int i ) {
217- Log .d (TAG , "HCEService:HeadlessJsTaskEventListener:onHeadlessJsTaskFinish: " + i );
254+ if (this .hceModule != null ) {
255+ this .hceModule .sendBackgroundEvent (prevBackgroundSessionUUID , "readerDeselected" , "" );
218256 }
219- });
220-
221- setupRunJSTask (reactContext );
257+ }
222258 }
223259
224- public void setupRunJSTask (@ NonNull ReactContext reactContext ) {
260+ public void setupRunJSTask (final @ NonNull ReactContext reactContext , final String useSessUUID ) {
225261 hceModule = (RTNHCEAndroidModule ) reactContext .getNativeModule ("NativeHCEModule" );
226262
227263 if (hceModule == null ) {
@@ -230,21 +266,19 @@ public void setupRunJSTask(@NonNull ReactContext reactContext) {
230266
231267 hceModule .setHCEService (this );
232268
233- UiThreadUtil .runOnUiThread (new Runnable () {
234- @ Override
235- public void run () {
236- Log .d (TAG , "HCEService:setupRunJSTask:runOnUiThread startTask" );
237- Bundle argBundle = new Bundle ();
238- argBundle .putString ("handle" , backgroundSessionUUID );
239- HeadlessJsTaskContext headlessJsTaskContext = Companion .getInstance (reactContext );
240- headlessJsTaskContext .startTask (
241- new HeadlessJsTaskConfig (
242- "handleBackgroundHCECall" ,
243- Arguments .fromBundle (argBundle ),
244- 15000 ,
245- false // not allowed in foreground
246- ));
247- }
269+ UiThreadUtil .runOnUiThread (() -> {
270+ Log .d (TAG , "HCEService:setupRunJSTask:runOnUiThread startTask" );
271+ Bundle argBundle = new Bundle ();
272+ argBundle .putString ("handle" , useSessUUID );
273+ HeadlessJsTaskContext headlessJsTaskContext = Companion .getInstance (reactContext );
274+ int taskId = headlessJsTaskContext .startTask (
275+ new HeadlessJsTaskConfig (
276+ "handleBackgroundHCECall" ,
277+ Arguments .fromBundle (argBundle ),
278+ 15000 ,
279+ false // not allowed in foreground
280+ ));
281+ taskSessionIdMap .put (useSessUUID , taskId );
248282 });
249283 }
250284
0 commit comments