Skip to content

Commit 8209825

Browse files
committed
frontend/android: move network related code to dedicated class
Our MainActivity code is quite complicated and mixes a lot of different things. This change moves the code related to network management (e.g. to display alerts when the network is not available) to a dedicated helper class and declutters the main activity a bit.
1 parent 6a24acd commit 8209825

File tree

2 files changed

+95
-72
lines changed

2 files changed

+95
-72
lines changed

frontends/android/BitBoxApp/app/src/main/java/ch/shiftcrypto/bitboxapp/MainActivity.java

Lines changed: 8 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@
1515
import android.hardware.usb.UsbDevice;
1616
import android.hardware.usb.UsbManager;
1717
import android.net.ConnectivityManager;
18-
import android.net.Network;
19-
import android.net.NetworkCapabilities;
20-
import android.net.NetworkRequest;
2118
import android.net.Uri;
2219
import android.os.Bundle;
2320
import android.os.Handler;
@@ -46,6 +43,7 @@ public class MainActivity extends AppCompatActivity {
4643
static {
4744
System.loadLibrary("signal_handler");
4845
}
46+
4947
public native void initsignalhandler();
5048
private final int PERMISSIONS_REQUEST_CAMERA_QRCODE = 0;
5149
private static final String ACTION_USB_PERMISSION = "ch.shiftcrypto.bitboxapp.USB_PERMISSION";
@@ -61,47 +59,7 @@ public class MainActivity extends AppCompatActivity {
6159
GoService goService;
6260

6361
private BitBoxWebChromeClient webChrome;
64-
65-
private ConnectivityManager connectivityManager;
66-
private ConnectivityManager.NetworkCallback networkCallback;
67-
68-
private boolean hasInternetConnectivity(NetworkCapabilities capabilities) {
69-
// To avoid false positives, if we can't obtain connectivity info,
70-
// we return true.
71-
// Note: this should never happen per Android documentation, as:
72-
// - these can not be null it come from the onCapabilitiesChanged callback.
73-
// - when obtained with getNetworkCapabilities(network), they can only be null if the
74-
// network is null or unknown, but we guard against both in the caller.
75-
if (capabilities == null) {
76-
Util.log("Got null capabilities when we shouldn't have. Assuming we are online.");
77-
return true;
78-
}
79-
80-
81-
boolean hasInternet = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
82-
83-
// We need to check for both internet and validated, since validated reports that the system
84-
// found connectivity the last time it checked. But if this callback triggers when going offline
85-
// (e.g. airplane mode), this bit would still be true when we execute this method.
86-
boolean isValidated = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
87-
return hasInternet && isValidated;
88-
89-
// Fallback for older devices
90-
}
91-
92-
private void checkConnectivity() {
93-
Network activeNetwork = connectivityManager.getActiveNetwork();
94-
95-
// If there is no active network (e.g. airplane mode), there is no check to perform.
96-
if (activeNetwork == null) {
97-
Mobileserver.setOnline(false);
98-
return;
99-
}
100-
101-
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(activeNetwork);
102-
103-
Mobileserver.setOnline(hasInternetConnectivity(capabilities));
104-
}
62+
private NetworkHelper networkHelper;
10563

10664
// Connection to bind with GoService
10765
private final ServiceConnection connection = new ServiceConnection() {
@@ -248,20 +206,8 @@ protected void onCreate(Bundle savedInstanceState) {
248206
// In that case, handleIntent() is not called with ACTION_USB_DEVICE_ATTACHED.
249207
this.updateDevice();
250208

251-
connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
252-
networkCallback = new ConnectivityManager.NetworkCallback() {
253-
@Override
254-
public void onCapabilitiesChanged(@NonNull android.net.Network network, @NonNull android.net.NetworkCapabilities capabilities) {
255-
super.onCapabilitiesChanged(network, capabilities);
256-
Mobileserver.setOnline(hasInternetConnectivity(capabilities));
257-
}
258-
// When we lose the network, onCapabilitiesChanged does not trigger, so we need to override onLost.
259-
@Override
260-
public void onLost(@NonNull Network network) {
261-
super.onLost(network);
262-
Mobileserver.setOnline(false);
263-
}
264-
};
209+
this.networkHelper = new NetworkHelper((ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE));
210+
265211

266212
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
267213
@Override
@@ -337,7 +283,7 @@ private void startServer() {
337283
goService.startServer(getApplicationContext().getFilesDir().getAbsolutePath(), gVM.getGoEnvironment(), gVM.getGoAPI());
338284

339285
// Trigger connectivity check (as the network may already be unavailable when the app starts).
340-
checkConnectivity();
286+
networkHelper.checkConnectivity();
341287
}
342288

343289
@Override
@@ -355,15 +301,7 @@ protected void onStart() {
355301
Util.log("lifecycle: onStart");
356302
final GoViewModel goViewModel = ViewModelProviders.of(this).get(GoViewModel.class);
357303
goViewModel.getIsDarkTheme().observe(this, this::setDarkTheme);
358-
359-
360-
NetworkRequest request = new NetworkRequest.Builder()
361-
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
362-
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
363-
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
364-
.build();
365-
// Register the network callback to listen for changes in network capabilities.
366-
connectivityManager.registerNetworkCallback(request, networkCallback);
304+
networkHelper.registerNetworkCallback();
367305
}
368306

369307
@Override
@@ -393,7 +331,7 @@ protected void onResume() {
393331
registerReceiver(this.networkStateReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
394332

395333
// Trigger connectivity check (as the network may already be unavailable when the app starts).
396-
checkConnectivity();
334+
networkHelper.checkConnectivity();
397335

398336
Intent intent = getIntent();
399337
handleIntent(intent);
@@ -472,9 +410,7 @@ private void updateDevice() {
472410
@Override
473411
protected void onStop() {
474412
super.onStop();
475-
if (connectivityManager != null && networkCallback != null) {
476-
connectivityManager.unregisterNetworkCallback(networkCallback);
477-
}
413+
networkHelper.unregisterNetworkCallback();
478414
Util.log("lifecycle: onStop");
479415
}
480416

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package ch.shiftcrypto.bitboxapp;
2+
3+
import android.net.ConnectivityManager;
4+
import android.net.Network;
5+
import android.net.NetworkCapabilities;
6+
import android.net.NetworkRequest;
7+
8+
import androidx.annotation.NonNull;
9+
10+
import mobileserver.Mobileserver;
11+
12+
public class NetworkHelper {
13+
private final ConnectivityManager connectivityManager;
14+
private final ConnectivityManager.NetworkCallback networkCallback;
15+
16+
public NetworkHelper(ConnectivityManager connectivityManager) {
17+
this.connectivityManager = connectivityManager;
18+
networkCallback = new ConnectivityManager.NetworkCallback() {
19+
@Override
20+
public void onCapabilitiesChanged(@NonNull android.net.Network network, @NonNull android.net.NetworkCapabilities capabilities) {
21+
super.onCapabilitiesChanged(network, capabilities);
22+
Mobileserver.setOnline(hasInternetConnectivity(capabilities));
23+
}
24+
// When we lose the network, onCapabilitiesChanged does not trigger, so we need to override onLost.
25+
@Override
26+
public void onLost(@NonNull Network network) {
27+
super.onLost(network);
28+
Mobileserver.setOnline(false);
29+
}
30+
};
31+
}
32+
33+
private boolean hasInternetConnectivity(NetworkCapabilities capabilities) {
34+
// To avoid false positives, if we can't obtain connectivity info,
35+
// we return true.
36+
// Note: this should never happen per Android documentation, as:
37+
// - these can not be null it come from the onCapabilitiesChanged callback.
38+
// - when obtained with getNetworkCapabilities(network), they can only be null if the
39+
// network is null or unknown, but we guard against both in the caller.
40+
if (capabilities == null) {
41+
Util.log("Got null capabilities when we shouldn't have. Assuming we are online.");
42+
return true;
43+
}
44+
45+
boolean hasInternet = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
46+
47+
// We need to check for both internet and validated, since validated reports that the system
48+
// found connectivity the last time it checked. But if this callback triggers when going offline
49+
// (e.g. airplane mode), this bit would still be true when we execute this method.
50+
boolean isValidated = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
51+
return hasInternet && isValidated;
52+
}
53+
54+
public void checkConnectivity() {
55+
Network activeNetwork = connectivityManager.getActiveNetwork();
56+
57+
// If there is no active network (e.g. airplane mode), there is no check to perform.
58+
if (activeNetwork == null) {
59+
Mobileserver.setOnline(false);
60+
return;
61+
}
62+
63+
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(activeNetwork);
64+
Mobileserver.setOnline(hasInternetConnectivity(capabilities));
65+
}
66+
67+
public void registerNetworkCallback() {
68+
if (connectivityManager == null) {
69+
return;
70+
}
71+
NetworkRequest request = new NetworkRequest.Builder()
72+
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
73+
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
74+
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
75+
.build();
76+
// Register the network callback to listen for changes in network capabilities.
77+
// It needs to be unregistered when the app is in background to avoid resources consumpion.
78+
// See https://developer.android.com/reference/android/net/ConnectivityManager#registerNetworkCallback(android.net.NetworkRequest,%20android.net.ConnectivityManager.NetworkCallback)
79+
connectivityManager.registerNetworkCallback(request, networkCallback);
80+
}
81+
82+
public void unregisterNetworkCallback() {
83+
if (connectivityManager != null && networkCallback != null) {
84+
connectivityManager.unregisterNetworkCallback(networkCallback);
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)