Skip to content

Commit a5f58d4

Browse files
authored
Merge eb98375 into cd268a3
2 parents cd268a3 + eb98375 commit a5f58d4

15 files changed

+450
-92
lines changed

sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
import io.sentry.DeduplicateMultithreadedEventProcessor;
99
import io.sentry.DefaultTransactionPerformanceCollector;
1010
import io.sentry.ILogger;
11+
import io.sentry.NoOpConnectionStatusProvider;
1112
import io.sentry.SendFireAndForgetEnvelopeSender;
1213
import io.sentry.SendFireAndForgetOutboxSender;
1314
import io.sentry.SentryLevel;
1415
import io.sentry.android.core.cache.AndroidEnvelopeCache;
1516
import io.sentry.android.core.internal.debugmeta.AssetsDebugMetaLoader;
1617
import io.sentry.android.core.internal.gestures.AndroidViewGestureTargetLocator;
1718
import io.sentry.android.core.internal.modules.AssetsModulesLoader;
19+
import io.sentry.android.core.internal.util.AndroidConnectionStatusProvider;
1820
import io.sentry.android.core.internal.util.AndroidMainThreadChecker;
1921
import io.sentry.android.core.internal.util.SentryFrameMetricsCollector;
2022
import io.sentry.android.fragment.FragmentLifecycleIntegration;
@@ -130,14 +132,19 @@ static void initializeIntegrationsAndProcessors(
130132
options.setEnvelopeDiskCache(new AndroidEnvelopeCache(options));
131133
}
132134

135+
if (options.getConnectionStatusProvider() instanceof NoOpConnectionStatusProvider) {
136+
options.setConnectionStatusProvider(
137+
new AndroidConnectionStatusProvider(context, options.getLogger(), buildInfoProvider));
138+
}
139+
133140
options.addEventProcessor(new DeduplicateMultithreadedEventProcessor(options));
134141
options.addEventProcessor(
135142
new DefaultAndroidEventProcessor(context, buildInfoProvider, options));
136143
options.addEventProcessor(new PerformanceAndroidEventProcessor(options, activityFramesTracker));
137144
options.addEventProcessor(new ScreenshotEventProcessor(options, buildInfoProvider));
138145
options.addEventProcessor(new ViewHierarchyEventProcessor(options));
139146
options.addEventProcessor(new AnrV2EventProcessor(context, options, buildInfoProvider));
140-
options.setTransportGate(new AndroidTransportGate(context, options.getLogger()));
147+
options.setTransportGate(new AndroidTransportGate(options));
141148
final SentryFrameMetricsCollector frameMetricsCollector =
142149
new SentryFrameMetricsCollector(context, options, buildInfoProvider);
143150
options.setTransactionProfiler(

sentry-android-core/src/main/java/io/sentry/android/core/AndroidTransportGate.java

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
11
package io.sentry.android.core;
22

3-
import android.content.Context;
4-
import io.sentry.ILogger;
5-
import io.sentry.android.core.internal.util.ConnectivityChecker;
3+
import io.sentry.IConnectionStatusProvider;
4+
import io.sentry.SentryOptions;
65
import io.sentry.transport.ITransportGate;
76
import org.jetbrains.annotations.NotNull;
87
import org.jetbrains.annotations.TestOnly;
98

109
final class AndroidTransportGate implements ITransportGate {
1110

12-
private final Context context;
13-
private final @NotNull ILogger logger;
11+
private final @NotNull SentryOptions options;
1412

15-
AndroidTransportGate(final @NotNull Context context, final @NotNull ILogger logger) {
16-
this.context = context;
17-
this.logger = logger;
13+
AndroidTransportGate(final @NotNull SentryOptions options) {
14+
this.options = options;
1815
}
1916

2017
@Override
2118
public boolean isConnected() {
22-
return isConnected(ConnectivityChecker.getConnectionStatus(context, logger));
19+
return isConnected(options.getConnectionStatusProvider().getConnectionStatus());
2320
}
2421

2522
@TestOnly
26-
boolean isConnected(final @NotNull ConnectivityChecker.Status status) {
23+
boolean isConnected(final @NotNull IConnectionStatusProvider.ConnectionStatus status) {
2724
// let's assume its connected if there's no permission or something as we can't really know
2825
// whether is online or not.
2926
switch (status) {

sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import android.util.DisplayMetrics;
1717
import io.sentry.DateUtils;
1818
import io.sentry.SentryLevel;
19-
import io.sentry.android.core.internal.util.ConnectivityChecker;
2019
import io.sentry.android.core.internal.util.CpuInfoUtils;
2120
import io.sentry.android.core.internal.util.DeviceOrientations;
2221
import io.sentry.android.core.internal.util.RootChecker;
@@ -180,8 +179,8 @@ private void setDeviceIO(final @NotNull Device device, final boolean includeDyna
180179
}
181180

182181
Boolean connected;
183-
switch (ConnectivityChecker.getConnectionStatus(context, options.getLogger())) {
184-
case NOT_CONNECTED:
182+
switch (options.getConnectionStatusProvider().getConnectionStatus()) {
183+
case DISCONNECTED:
185184
connected = false;
186185
break;
187186
case CONNECTED:
@@ -223,8 +222,7 @@ private void setDeviceIO(final @NotNull Device device, final boolean includeDyna
223222

224223
if (device.getConnectionType() == null) {
225224
// wifi, ethernet or cellular, null if none
226-
device.setConnectionType(
227-
ConnectivityChecker.getConnectionType(context, options.getLogger(), buildInfoProvider));
225+
device.setConnectionType(options.getConnectionStatusProvider().getConnectionType());
228226
}
229227
}
230228

sentry-android-core/src/main/java/io/sentry/android/core/NetworkBreadcrumbsIntegration.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import io.sentry.SentryLevel;
1717
import io.sentry.SentryOptions;
1818
import io.sentry.TypeCheckHint;
19-
import io.sentry.android.core.internal.util.ConnectivityChecker;
19+
import io.sentry.android.core.internal.util.AndroidConnectionStatusProvider;
2020
import io.sentry.util.Objects;
2121
import java.io.Closeable;
2222
import java.io.IOException;
@@ -69,7 +69,7 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio
6969

7070
networkCallback = new NetworkBreadcrumbsNetworkCallback(hub, buildInfoProvider);
7171
final boolean registered =
72-
ConnectivityChecker.registerNetworkCallback(
72+
AndroidConnectionStatusProvider.registerNetworkCallback(
7373
context, logger, buildInfoProvider, networkCallback);
7474

7575
// The specific error is logged in the ConnectivityChecker method
@@ -86,7 +86,7 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio
8686
@Override
8787
public void close() throws IOException {
8888
if (networkCallback != null) {
89-
ConnectivityChecker.unregisterNetworkCallback(
89+
AndroidConnectionStatusProvider.unregisterNetworkCallback(
9090
context, logger, buildInfoProvider, networkCallback);
9191
logger.log(SentryLevel.DEBUG, "NetworkBreadcrumbsIntegration remove.");
9292
}
@@ -208,7 +208,7 @@ static class NetworkBreadcrumbConnectionDetail {
208208
this.signalStrength = strength > -100 ? strength : 0;
209209
this.isVpn = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
210210
String connectionType =
211-
ConnectivityChecker.getConnectionType(networkCapabilities, buildInfoProvider);
211+
AndroidConnectionStatusProvider.getConnectionType(networkCapabilities, buildInfoProvider);
212212
this.type = connectionType != null ? connectionType : "";
213213
}
214214

sentry-android-core/src/main/java/io/sentry/android/core/internal/util/ConnectivityChecker.java renamed to sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProvider.java

Lines changed: 82 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,48 @@
77
import android.net.Network;
88
import android.net.NetworkCapabilities;
99
import android.os.Build;
10+
import androidx.annotation.NonNull;
11+
import androidx.annotation.RequiresApi;
12+
import io.sentry.IConnectionStatusProvider;
1013
import io.sentry.ILogger;
1114
import io.sentry.SentryLevel;
1215
import io.sentry.android.core.BuildInfoProvider;
16+
import java.util.HashMap;
17+
import java.util.Map;
1318
import org.jetbrains.annotations.ApiStatus;
1419
import org.jetbrains.annotations.NotNull;
1520
import org.jetbrains.annotations.Nullable;
21+
import org.jetbrains.annotations.TestOnly;
1622

1723
/**
1824
* Note: ConnectivityManager sometimes throws SecurityExceptions on Android 11. Hence all relevant
1925
* calls are guarded with try/catch. see https://issuetracker.google.com/issues/175055271 for more
2026
* details
2127
*/
2228
@ApiStatus.Internal
23-
public final class ConnectivityChecker {
29+
public final class AndroidConnectionStatusProvider implements IConnectionStatusProvider {
2430

25-
public enum Status {
26-
CONNECTED,
27-
NOT_CONNECTED,
28-
NO_PERMISSION,
29-
UNKNOWN
30-
}
31+
private final @NotNull Context context;
32+
private final @NotNull ILogger logger;
33+
private final @NotNull BuildInfoProvider buildInfoProvider;
34+
private final @NotNull Map<IConnectionStatusObserver, ConnectivityManager.NetworkCallback>
35+
registeredCallbacks;
3136

32-
private ConnectivityChecker() {}
37+
public AndroidConnectionStatusProvider(
38+
@NotNull Context context,
39+
@NotNull ILogger logger,
40+
@NotNull BuildInfoProvider buildInfoProvider) {
41+
this.context = context;
42+
this.logger = logger;
43+
this.buildInfoProvider = buildInfoProvider;
44+
this.registeredCallbacks = new HashMap<>();
45+
}
3346

34-
/**
35-
* Return the Connection status
36-
*
37-
* @return the ConnectionStatus
38-
*/
39-
public static @NotNull ConnectivityChecker.Status getConnectionStatus(
40-
final @NotNull Context context, final @NotNull ILogger logger) {
47+
@Override
48+
public @NotNull ConnectionStatus getConnectionStatus() {
4149
final ConnectivityManager connectivityManager = getConnectivityManager(context, logger);
4250
if (connectivityManager == null) {
43-
return Status.UNKNOWN;
51+
return ConnectionStatus.UNKNOWN;
4452
}
4553
return getConnectionStatus(context, connectivityManager, logger);
4654
// getActiveNetworkInfo might return null if VPN doesn't specify its
@@ -50,6 +58,50 @@ private ConnectivityChecker() {}
5058
// connectivityManager.registerDefaultNetworkCallback(...)
5159
}
5260

61+
@Override
62+
public @Nullable String getConnectionType() {
63+
return getConnectionType(context, logger, buildInfoProvider);
64+
}
65+
66+
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
67+
@Override
68+
public boolean addConnectionStatusObserver(@NotNull IConnectionStatusObserver observer) {
69+
final ConnectivityManager.NetworkCallback callback =
70+
new ConnectivityManager.NetworkCallback() {
71+
@Override
72+
public void onAvailable(@NonNull Network network) {
73+
observer.onConnectionStatusChanged(getConnectionStatus());
74+
}
75+
76+
@Override
77+
public void onLosing(@NonNull Network network, int maxMsToLive) {
78+
observer.onConnectionStatusChanged(getConnectionStatus());
79+
}
80+
81+
@Override
82+
public void onLost(@NonNull Network network) {
83+
observer.onConnectionStatusChanged(getConnectionStatus());
84+
}
85+
86+
@Override
87+
public void onUnavailable() {
88+
observer.onConnectionStatusChanged(getConnectionStatus());
89+
}
90+
};
91+
92+
registeredCallbacks.put(observer, callback);
93+
return registerNetworkCallback(context, logger, buildInfoProvider, callback);
94+
}
95+
96+
@Override
97+
public void removeConnectionStatusObserver(@NotNull IConnectionStatusObserver observer) {
98+
final @Nullable ConnectivityManager.NetworkCallback callback =
99+
registeredCallbacks.remove(observer);
100+
if (callback != null) {
101+
unregisterNetworkCallback(context, logger, buildInfoProvider, callback);
102+
}
103+
}
104+
53105
/**
54106
* Return the Connection status
55107
*
@@ -59,25 +111,27 @@ private ConnectivityChecker() {}
59111
* @return true if connected or no permission to check, false otherwise
60112
*/
61113
@SuppressWarnings({"deprecation", "MissingPermission"})
62-
private static @NotNull ConnectivityChecker.Status getConnectionStatus(
114+
private static @NotNull IConnectionStatusProvider.ConnectionStatus getConnectionStatus(
63115
final @NotNull Context context,
64116
final @NotNull ConnectivityManager connectivityManager,
65117
final @NotNull ILogger logger) {
66118
if (!Permissions.hasPermission(context, Manifest.permission.ACCESS_NETWORK_STATE)) {
67119
logger.log(SentryLevel.INFO, "No permission (ACCESS_NETWORK_STATE) to check network status.");
68-
return Status.NO_PERMISSION;
120+
return ConnectionStatus.NO_PERMISSION;
69121
}
70122

71123
try {
72124
final android.net.NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
73125
if (activeNetworkInfo == null) {
74126
logger.log(SentryLevel.INFO, "NetworkInfo is null, there's no active network.");
75-
return Status.NOT_CONNECTED;
127+
return ConnectionStatus.DISCONNECTED;
76128
}
77-
return activeNetworkInfo.isConnected() ? Status.CONNECTED : Status.NOT_CONNECTED;
129+
return activeNetworkInfo.isConnected()
130+
? ConnectionStatus.CONNECTED
131+
: ConnectionStatus.DISCONNECTED;
78132
} catch (Throwable t) {
79133
logger.log(SentryLevel.ERROR, "Could not retrieve Connection Status", t);
80-
return Status.UNKNOWN;
134+
return ConnectionStatus.UNKNOWN;
81135
}
82136
}
83137

@@ -273,4 +327,11 @@ public static void unregisterNetworkCallback(
273327
logger.log(SentryLevel.ERROR, "unregisterNetworkCallback failed", t);
274328
}
275329
}
330+
331+
@TestOnly
332+
@NotNull
333+
public Map<IConnectionStatusObserver, ConnectivityManager.NetworkCallback>
334+
getRegisteredCallbacks() {
335+
return registeredCallbacks;
336+
}
276337
}

0 commit comments

Comments
 (0)