4
4
import android .annotation .SuppressLint ;
5
5
import android .content .Context ;
6
6
import android .net .ConnectivityManager ;
7
+ import android .net .LinkAddress ;
8
+ import android .net .LinkProperties ;
7
9
import android .net .Network ;
8
10
import android .net .NetworkCapabilities ;
9
11
import android .net .NetworkRequest ;
18
20
import com .facebook .react .bridge .ReadableMap ;
19
21
20
22
import java .io .IOException ;
23
+ import java .net .Inet4Address ;
24
+ import java .util .ArrayList ;
25
+ import java .util .List ;
26
+ import java .util .Objects ;
21
27
import java .util .concurrent .ConcurrentHashMap ;
22
28
import java .util .concurrent .CountDownLatch ;
23
29
import java .util .concurrent .ExecutorService ;
@@ -76,7 +82,9 @@ public void run() {
76
82
// Get the network interface
77
83
final String localAddress = options .hasKey ("localAddress" ) ? options .getString ("localAddress" ) : null ;
78
84
final String iface = options .hasKey ("interface" ) ? options .getString ("interface" ) : null ;
79
- selectNetwork (iface , localAddress );
85
+ // Get ioT device host to retreive correct network in android concurrent connections
86
+ final String iotDeviceHost = options .hasKey ("host" ) ? options .getString ("host" ) : null ;
87
+ selectNetwork (iface , localAddress , iotDeviceHost );
80
88
TcpSocketClient client = new TcpSocketClient (tcpEvtListener , cId , null );
81
89
socketMap .put (cId , client );
82
90
ReadableMap tlsOptions = pendingTLS .get (cId );
@@ -213,23 +221,99 @@ public void removeListeners(Integer count) {
213
221
// Keep: Required for RN built in Event Emitter Calls.
214
222
}
215
223
216
- private void requestNetwork (final int transportType ) throws InterruptedException {
224
+ private void requestNetwork (final int transportType , @ Nullable final String iotDeviceHost ) throws InterruptedException {
217
225
final NetworkRequest .Builder requestBuilder = new NetworkRequest .Builder ();
218
226
requestBuilder .addTransportType (transportType );
219
227
final CountDownLatch awaitingNetwork = new CountDownLatch (1 ); // only needs to be counted down once to release waiting threads
220
228
final ConnectivityManager cm = (ConnectivityManager ) mReactContext .getSystemService (Context .CONNECTIVITY_SERVICE );
221
- cm .requestNetwork (requestBuilder .build (), new ConnectivityManager .NetworkCallback () {
222
- @ Override
223
- public void onAvailable (Network network ) {
224
- currentNetwork .setNetwork (network );
225
- awaitingNetwork .countDown (); // Stop waiting
226
- }
227
229
228
- @ Override
229
- public void onUnavailable () {
230
+ if (iotDeviceHost ==null || Objects .equals (iotDeviceHost , "localhost" )) {
231
+ // Use old behavior if "host" param not specified on configuration array - default value "localhost" used
232
+ cm .requestNetwork (requestBuilder .build (), new ConnectivityManager .NetworkCallback () {
233
+ @ Override
234
+ public void onAvailable (Network network ) {
235
+ currentNetwork .setNetwork (network );
236
+ awaitingNetwork .countDown (); // Stop waiting
237
+ }
238
+
239
+ @ Override
240
+ public void onUnavailable () {
241
+ awaitingNetwork .countDown (); // Stop waiting
242
+ }
243
+ });
244
+ } else {
245
+ // smartmedev - add support for for concurrent-connections:
246
+ // Route all data to the ioT device network interface if exist more than one concurrent network
247
+ // See: https://developer.android.com/about/versions/12/behavior-changes-12#concurrent-connections
248
+ if (cm != null ) {
249
+ // Get all connected networks
250
+ Network [] allNetworks = cm .getAllNetworks ();
251
+ List <Network > wifiNetworks = new ArrayList <>();
252
+
253
+ // Check exist at least one newtwork
254
+ if (allNetworks != null && allNetworks .length > 0 ) {
255
+ // Filter for retreive only networks based on selected transport type
256
+ for (Network network : allNetworks ) {
257
+ NetworkCapabilities nc = cm .getNetworkCapabilities (network );
258
+ if (nc != null && nc .hasTransport (transportType )) {
259
+ wifiNetworks .add (network );
260
+ }
261
+ }
262
+
263
+ // Check exist at least one newtwork based on selected transport type
264
+ if (!wifiNetworks .isEmpty ()) {
265
+ boolean networkFound = false ;
266
+ for (Network network : wifiNetworks ) {
267
+ LinkProperties linkProperties = cm .getLinkProperties (network );
268
+ // Ensure linkProperties is not null
269
+ if (linkProperties == null )
270
+ continue ;
271
+
272
+ if (android .os .Build .VERSION .SDK_INT >= android .os .Build .VERSION_CODES .R ) {
273
+ Inet4Address foundServerAddress = linkProperties .getDhcpServerAddress ();
274
+ if (iotDeviceHost .equals (foundServerAddress .getHostAddress ())) {
275
+ // found ioT device network
276
+ currentNetwork .setNetwork (network );
277
+ cm .bindProcessToNetwork (network );
278
+ networkFound = true ;
279
+ awaitingNetwork .countDown (); // Stop waiting
280
+ break ;
281
+ }
282
+ } else {
283
+ List <LinkAddress > linkAddressList = linkProperties .getLinkAddresses ();
284
+ if (linkAddressList != null && !linkAddressList .isEmpty ()) {
285
+ for (LinkAddress address : linkAddressList ) {
286
+ int lastDotIndex = iotDeviceHost .lastIndexOf ('.' );
287
+ String iotSubnetAddress = iotDeviceHost ;
288
+ if (lastDotIndex >=0 )
289
+ iotSubnetAddress = iotDeviceHost .substring (0 , lastDotIndex );
290
+ if (address .getAddress ().getHostAddress ().startsWith (iotSubnetAddress )) {
291
+ // found ioT device network
292
+ currentNetwork .setNetwork (network );
293
+ cm .bindProcessToNetwork (network );
294
+ networkFound = true ;
295
+ awaitingNetwork .countDown (); // Stop waiting
296
+ break ;
297
+ }
298
+ }
299
+ }
300
+ }
301
+ }
302
+ if (!networkFound ) {
303
+ awaitingNetwork .countDown (); // Stop waiting if no network was found
304
+ }
305
+ } else {
306
+ awaitingNetwork .countDown (); // Stop waiting
307
+ }
308
+ } else {
309
+ awaitingNetwork .countDown (); // Stop waiting
310
+ }
311
+ } else {
230
312
awaitingNetwork .countDown (); // Stop waiting
231
313
}
232
- });
314
+ // smartmedev - end
315
+ }
316
+
233
317
// Timeout if there the network is unreachable
234
318
ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor (1 );
235
319
exec .schedule (new Runnable () {
@@ -248,7 +332,7 @@ public void run() {
248
332
* "cellular" -> Cellular
249
333
* etc...
250
334
*/
251
- private void selectNetwork (@ Nullable final String iface , @ Nullable final String ipAddress ) throws InterruptedException , IOException {
335
+ private void selectNetwork (@ Nullable final String iface , @ Nullable final String ipAddress , @ Nullable final String iotDeviceHost ) throws InterruptedException , IOException {
252
336
currentNetwork .setNetwork (null );
253
337
if (iface == null ) return ;
254
338
if (ipAddress != null ) {
@@ -260,13 +344,13 @@ private void selectNetwork(@Nullable final String iface, @Nullable final String
260
344
}
261
345
switch (iface ) {
262
346
case "wifi" :
263
- requestNetwork (NetworkCapabilities .TRANSPORT_WIFI );
347
+ requestNetwork (NetworkCapabilities .TRANSPORT_WIFI , iotDeviceHost );
264
348
break ;
265
349
case "cellular" :
266
- requestNetwork (NetworkCapabilities .TRANSPORT_CELLULAR );
350
+ requestNetwork (NetworkCapabilities .TRANSPORT_CELLULAR , iotDeviceHost );
267
351
break ;
268
352
case "ethernet" :
269
- requestNetwork (NetworkCapabilities .TRANSPORT_ETHERNET );
353
+ requestNetwork (NetworkCapabilities .TRANSPORT_ETHERNET , iotDeviceHost );
270
354
break ;
271
355
}
272
356
if (currentNetwork .getNetwork () == null ) {
0 commit comments