Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor network detectors to kotlin #752

Merged
merged 11 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ public Builder carrier(@Nullable Carrier carrier) {
}

public Builder subType(@Nullable String subType) {
if ((subType != null) && subType.isEmpty()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if ((subType != null) && subType.isEmpty()) {
if ((subType.isNullOrEmpty()) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That will NPE right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

@breedx-splk breedx-splk Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is indeed super nice! And does this also monkey patch the java classes? Because this is still java.....

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I won't work from Java, though maybe we can take the opportunity to switch it to Kotlin? It doesn't seem like it'll be a complicated class to change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could subType?.isNullOrEmpty() ?: true or similar with Java interop.

return subType(null);
}
this.subType = subType;
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import static org.mockito.Mockito.when;

import android.app.Application;
import android.net.ConnectivityManager;
import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.test.ext.junit.runners.AndroidJUnit4;
Expand Down Expand Up @@ -98,13 +99,16 @@ public class OpenTelemetryRumBuilderTest {
@Mock android.content.Context applicationContext;

@Mock InitializationEvents initializationEvents;
@Mock ConnectivityManager connectivityManager;
private AutoCloseable mocks;

@Before
public void setup() {
mocks = MockitoAnnotations.openMocks(this);
when(application.getApplicationContext()).thenReturn(applicationContext);
when(application.getMainLooper()).thenReturn(looper);
when(application.getSystemService(android.content.Context.CONNECTIVITY_SERVICE))
.thenReturn(connectivityManager);
InitializationEvents.set(initializationEvents);
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.internal.services.network.detector

import android.content.Context
import android.net.ConnectivityManager
import android.os.Build
import android.telephony.TelephonyManager
import io.opentelemetry.android.common.internal.features.networkattributes.data.CurrentNetwork
import io.opentelemetry.android.internal.services.network.CarrierFinder

/**
* This class is internal and not for public use. Its APIs are unstable and can change at any time.
*/
interface NetworkDetector {
fun detectCurrentNetwork(): CurrentNetwork

companion object {
@JvmStatic
fun create(context: Context): NetworkDetector {
// TODO: Use ServiceManager to get the ConnectivityManager or similar (not yet managed/abstracted)
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// TODO: Use ServiceManager to get the TelephonyManager or similar (not yet managed/abstracted)
val telephonyManager =
context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
val carrierFinder = CarrierFinder(telephonyManager)
return PostApi28NetworkDetector(
connectivityManager,
telephonyManager,
carrierFinder,
context,
)
}
return SimpleNetworkDetector(connectivityManager)
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.android.internal.services.network.detector

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.telephony.TelephonyManager
import android.telephony.TelephonyManager.NETWORK_TYPE_1xRTT
import android.telephony.TelephonyManager.NETWORK_TYPE_CDMA
import android.telephony.TelephonyManager.NETWORK_TYPE_EDGE
import android.telephony.TelephonyManager.NETWORK_TYPE_EHRPD
import android.telephony.TelephonyManager.NETWORK_TYPE_EVDO_0
import android.telephony.TelephonyManager.NETWORK_TYPE_EVDO_A
import android.telephony.TelephonyManager.NETWORK_TYPE_EVDO_B
import android.telephony.TelephonyManager.NETWORK_TYPE_GPRS
import android.telephony.TelephonyManager.NETWORK_TYPE_GSM
import android.telephony.TelephonyManager.NETWORK_TYPE_HSDPA
import android.telephony.TelephonyManager.NETWORK_TYPE_HSPA
import android.telephony.TelephonyManager.NETWORK_TYPE_HSPAP
import android.telephony.TelephonyManager.NETWORK_TYPE_HSUPA
import android.telephony.TelephonyManager.NETWORK_TYPE_IDEN
import android.telephony.TelephonyManager.NETWORK_TYPE_IWLAN
import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
import android.telephony.TelephonyManager.NETWORK_TYPE_NR
import android.telephony.TelephonyManager.NETWORK_TYPE_TD_SCDMA
import android.telephony.TelephonyManager.NETWORK_TYPE_UMTS
import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import io.opentelemetry.android.common.internal.features.networkattributes.data.Carrier
import io.opentelemetry.android.common.internal.features.networkattributes.data.CurrentNetwork
import io.opentelemetry.android.common.internal.features.networkattributes.data.NetworkState
import io.opentelemetry.android.common.internal.features.networkattributes.data.NetworkState.TRANSPORT_CELLULAR
import io.opentelemetry.android.common.internal.features.networkattributes.data.NetworkState.TRANSPORT_VPN
import io.opentelemetry.android.common.internal.features.networkattributes.data.NetworkState.TRANSPORT_WIFI
import io.opentelemetry.android.internal.services.network.CarrierFinder
import io.opentelemetry.android.internal.services.network.CurrentNetworkProvider
import io.opentelemetry.android.internal.services.network.CurrentNetworkProvider.UNKNOWN_NETWORK

/**
* This class is internal and not for public use. Its APIs are unstable and can change at any time.
*/
@RequiresApi(api = Build.VERSION_CODES.P)
internal class PostApi28NetworkDetector
@JvmOverloads
constructor(
private val connectivityManager: ConnectivityManager,
private val telephonyManager: TelephonyManager,
private val carrierFinder: CarrierFinder,
private val context: Context,
private val readPhoneState: () -> Boolean = { canReadPhoneState(context) },
) : NetworkDetector {
@SuppressLint("MissingPermission")
override fun detectCurrentNetwork(): CurrentNetwork {
val capabilities =
connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
?: return CurrentNetworkProvider.NO_NETWORK
val carrier = carrierFinder.get()

fun hasTransport(transportId: Int): Boolean = capabilities.hasTransport(transportId)

val network = buildFromCarrier(carrier)
return when {
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> withCellDataType(carrier)
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> network(TRANSPORT_WIFI)
hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> network(TRANSPORT_VPN)
else -> UNKNOWN_NETWORK
}
}

private fun buildFromCarrier(carrier: Carrier): (NetworkState) -> CurrentNetwork =
{ CurrentNetwork.builder(it).carrier(carrier).build() }

private fun withCellDataType(carrier: Carrier): CurrentNetwork {
val builder =
CurrentNetwork
.builder(TRANSPORT_CELLULAR)
.carrier(carrier)
if (readPhoneState()) {
val dataNetworkType = getDataNetworkTypeName(telephonyManager.dataNetworkType)
return builder.subType(dataNetworkType).build()
}
return builder.build()
}

private fun getDataNetworkTypeName(dataNetworkType: Int): String =
when (dataNetworkType) {
NETWORK_TYPE_1xRTT -> "1xRTT"
NETWORK_TYPE_CDMA -> "CDMA"
NETWORK_TYPE_EDGE -> "EDGE"
NETWORK_TYPE_EHRPD -> "EHRPD"
NETWORK_TYPE_EVDO_0 -> "EVDO_0"
NETWORK_TYPE_EVDO_A -> "EVDO_A"
NETWORK_TYPE_EVDO_B -> "EVDO_B"
NETWORK_TYPE_GPRS -> "GPRS"
NETWORK_TYPE_GSM -> "GSM"
NETWORK_TYPE_HSDPA -> "HSDPA"
NETWORK_TYPE_HSPA -> "HSPA"
NETWORK_TYPE_HSPAP -> "HSPAP"
NETWORK_TYPE_HSUPA -> "HSUPA"
NETWORK_TYPE_IDEN -> "IDEN"
NETWORK_TYPE_IWLAN -> "IWLAN"
NETWORK_TYPE_LTE -> "LTE"
NETWORK_TYPE_NR -> "NR"
NETWORK_TYPE_TD_SCDMA -> "SCDMA"
NETWORK_TYPE_UMTS -> "UMTS"
NETWORK_TYPE_UNKNOWN -> "UNKNOWN"
else -> "UNKNOWN"
}
}

// visible for testing
fun canReadPhoneState(context: Context): Boolean =
(
ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED
)
Loading
Loading