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

feat(android, ios): add 5G support #130

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
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
168 changes: 135 additions & 33 deletions src/android/NetworkManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,27 @@ Licensed to the Apache Software Foundation (ASF) under one
import org.apache.cordova.PluginResult;
import org.apache.cordova.CordovaWebView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.telephony.ServiceState;

import androidx.core.app.ActivityCompat;

import java.util.Locale;

import static android.telephony.PhoneStateListener.LISTEN_SERVICE_STATE;

public class NetworkManager extends CordovaPlugin {

public static int NOT_REACHABLE = 0;
Expand All @@ -51,12 +59,12 @@ public class NetworkManager extends CordovaPlugin {

// Android L calls this Cellular, because I have no idea!
public static final String CELLULAR = "cellular";
// 2G network types
// 2G network types
public static final String TWO_G = "2g";
public static final String GSM = "gsm";
public static final String GPRS = "gprs";
public static final String EDGE = "edge";
// 3G network types
// 3G network types
public static final String THREE_G = "3g";
public static final String CDMA = "cdma";
public static final String UMTS = "umts";
Expand All @@ -70,6 +78,11 @@ public class NetworkManager extends CordovaPlugin {
public static final String LTE = "lte";
public static final String UMB = "umb";
public static final String HSPA_PLUS = "hspa+";

// 5G network types
public static final String FIVE_G = "5g";
public static final String NR = "nr";

// return type
public static final String TYPE_UNKNOWN = "unknown";
public static final String TYPE_ETHERNET = "ethernet";
Expand All @@ -78,15 +91,21 @@ public class NetworkManager extends CordovaPlugin {
public static final String TYPE_2G = "2g";
public static final String TYPE_3G = "3g";
public static final String TYPE_4G = "4g";
public static final String TYPE_5G = "5g";
public static final String TYPE_NONE = "none";

public static final int NETWORK_TYPE_NR = 20;
public static final int NETWORK_TYPE_LTE_CA = 19;

private static final String LOG_TAG = "NetworkManager";

private CallbackContext connectionCallbackContext;

ConnectivityManager sockMan;
BroadcastReceiver receiver;
private String lastTypeOfNetwork;
private String lastTypeOfNetwork = TYPE_UNKNOWN;
TelephonyManager telMan;
private static boolean isNrAvailable;

/**
* Sets the context of the Command. This can then be used to do things like
Expand All @@ -98,6 +117,8 @@ public class NetworkManager extends CordovaPlugin {
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
ZumelzuR marked this conversation as resolved.
Show resolved Hide resolved
super.initialize(cordova, webView);
this.sockMan = (ConnectivityManager) cordova.getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
this.telMan = (TelephonyManager) cordova.getActivity().getSystemService(Context.TELEPHONY_SERVICE);
this.telMan.listen( phoneStateListener, LISTEN_SERVICE_STATE);
this.connectionCallbackContext = null;

this.registerConnectivityActionReceiver();
Expand Down Expand Up @@ -158,7 +179,7 @@ private void registerConnectivityActionReceiver() {
public void onReceive(Context context, Intent intent) {
// (The null check is for the ARM Emulator, please use Intel Emulator for better results)
if (NetworkManager.this.webView != null) {
updateConnectionInfo(sockMan.getActiveNetworkInfo());
updateConnectionInfo(sockMan.getActiveNetworkInfo(), true);
}

String connectionType;
Expand Down Expand Up @@ -204,10 +225,10 @@ private void unregisterReceiver() {
* @param info the current active network info
* @return
*/
private void updateConnectionInfo(NetworkInfo info) {
private void updateConnectionInfo(NetworkInfo info, boolean forceRefresh) {
// send update to javascript "navigator.connection"
// Jellybean sends its own info
String currentNetworkType = this.getTypeOfNetworkFallbackToTypeNoneIfNotConnected(info);
String currentNetworkType = this.getTypeOfNetworkFallbackToTypeNoneIfNotConnected(info, forceRefresh);
if (currentNetworkType.equals(this.lastTypeOfNetwork)) {
LOG.d(LOG_TAG, "Networkinfo state didn't change, there is no event propagated to the JavaScript side.");
} else {
Expand All @@ -222,16 +243,19 @@ private void updateConnectionInfo(NetworkInfo info) {
* @param info the current active network info
* @return type the type of network
*/
private String getTypeOfNetworkFallbackToTypeNoneIfNotConnected(NetworkInfo info) {
private String getTypeOfNetworkFallbackToTypeNoneIfNotConnected(NetworkInfo info, Boolean forceRefresh) {
// the info might still be null in this part of the code
String type;
if (info != null) {
// If we are not connected to any network set type to none
if (!info.isConnected()) {
type = TYPE_NONE;
}
else {
type = getType(info);
} else {
if(lastTypeOfNetwork.equals(TYPE_UNKNOWN) || forceRefresh) {
type = getType(info);
} else {
type = lastTypeOfNetwork;
}
}
} else {
type = TYPE_NONE;
Expand All @@ -240,6 +264,10 @@ private String getTypeOfNetworkFallbackToTypeNoneIfNotConnected(NetworkInfo info
LOG.d(LOG_TAG, "Connection Type: " + type);
return type;
}
private String getTypeOfNetworkFallbackToTypeNoneIfNotConnected(NetworkInfo info) {
ZumelzuR marked this conversation as resolved.
Show resolved Hide resolved
// the info might still be null in this part of the code
return this.getTypeOfNetworkFallbackToTypeNoneIfNotConnected(info, false);
}

/**
* Create a new plugin result and send it back to JavaScript
Expand All @@ -259,7 +287,7 @@ private void sendUpdate(String type) {
* Determine the type of connection
*
* @param info the network info so we can determine connection type.
* @return the type of mobile network we are on
* @return the type of network we are on
*/
private String getType(NetworkInfo info) {
String type = info.getTypeName().toLowerCase(Locale.US);
Expand All @@ -270,28 +298,102 @@ private String getType(NetworkInfo info) {
} else if (type.toLowerCase().equals(TYPE_ETHERNET) || type.toLowerCase().startsWith(TYPE_ETHERNET_SHORT)) {
return TYPE_ETHERNET;
} else if (type.equals(MOBILE) || type.equals(CELLULAR)) {
type = info.getSubtypeName().toLowerCase(Locale.US);
if (type.equals(GSM) ||
type.equals(GPRS) ||
type.equals(EDGE) ||
type.equals(TWO_G)) {
return TYPE_2G;
} else if (type.startsWith(CDMA) ||
type.equals(UMTS) ||
type.equals(ONEXRTT) ||
type.equals(EHRPD) ||
type.equals(HSUPA) ||
type.equals(HSDPA) ||
type.equals(HSPA) ||
type.equals(THREE_G)) {
return TYPE_3G;
} else if (type.equals(LTE) ||
type.equals(UMB) ||
type.equals(HSPA_PLUS) ||
type.equals(FOUR_G)) {
return TYPE_4G;
return getMobileType(info);
}
return TYPE_UNKNOWN;
}

/**
* Determine the subtype of mobile connection
*
* @param info the network info so we can determine connection type.
* @return the type of mobile network we are on
*/
private String getMobileType(NetworkInfo info){
int subTypeId = info.getSubtype();
String subTypeName = info.getSubtypeName().toLowerCase(Locale.US);
if(is2G(subTypeId, subTypeName)){
return TYPE_2G;
} else if(is3G(subTypeId, subTypeName)) {
return TYPE_3G;
} else if(is4G(subTypeId, subTypeName)) {
if(isNrAvailable){ // if is LTE network could be 5g if NR is available
return TYPE_5G;
}
return TYPE_4G;
} else if(is5G(subTypeId, subTypeName)) {
return TYPE_5G;
}
return TYPE_UNKNOWN;
}

private boolean is2G(int type, String name){
return type == TelephonyManager.NETWORK_TYPE_GPRS ||
type == TelephonyManager.NETWORK_TYPE_EDGE ||
type == TelephonyManager.NETWORK_TYPE_CDMA ||
type == TelephonyManager.NETWORK_TYPE_1xRTT ||
type == TelephonyManager.NETWORK_TYPE_IDEN || // api< 8: replace by 11
type == TelephonyManager.NETWORK_TYPE_GSM || // api<25: replace by 16
name.equals(GSM) ||
name.equals(GPRS) ||
name.equals(EDGE) ||
name.equals(TWO_G);
}

private boolean is3G(int type, String name){
return type == TelephonyManager.NETWORK_TYPE_UMTS ||
type == TelephonyManager.NETWORK_TYPE_EVDO_0 ||
type == TelephonyManager.NETWORK_TYPE_EVDO_A ||
type == TelephonyManager.NETWORK_TYPE_HSDPA ||
type == TelephonyManager.NETWORK_TYPE_HSUPA ||
type == TelephonyManager.NETWORK_TYPE_HSPA ||
type == TelephonyManager.NETWORK_TYPE_EVDO_B || // api< 9: replace by 12
type == TelephonyManager.NETWORK_TYPE_EHRPD || // api<11: replace by 14
type == TelephonyManager.NETWORK_TYPE_HSPAP || // api<13: replace by 15
type == TelephonyManager.NETWORK_TYPE_TD_SCDMA || // api<25: replace by 17
name.startsWith(CDMA) ||
name.equals(UMTS) ||
name.equals(ONEXRTT) ||
name.equals(EHRPD) ||
name.equals(HSUPA) ||
name.equals(HSDPA) ||
name.equals(HSPA) ||
name.equals(THREE_G);
}

private boolean is4G(int type, String name){
return type == TelephonyManager.NETWORK_TYPE_LTE && name.equals(FOUR_G) || // api<11: replace by 13
type == TelephonyManager.NETWORK_TYPE_IWLAN || // api<25: replace by 18
type == NETWORK_TYPE_LTE_CA || // LTE_CA
name.equals(LTE) ||
name.equals(UMB) ||
name.equals(HSPA_PLUS) ||
name.equals(FOUR_G);
}

private boolean is5G(int type, String name){
return type == TelephonyManager.NETWORK_TYPE_LTE && name.equals(FIVE_G) || // api<11: replace by 13
type == NETWORK_TYPE_NR || // api<25: replace by 18
name.equals(FIVE_G) ||
name.equals(NR);
}

private PhoneStateListener phoneStateListener = new PhoneStateListener() {
@Override
public void onServiceStateChanged(ServiceState serviceState) {
NetworkManager.this.isNrAvailable = isNrAvailable(serviceState);
updateConnectionInfo(sockMan.getActiveNetworkInfo(), true);
}
};

/**
* Determine if NR network is available, for detect sdk < 30
*
* @param serviceState the ServiceState from PhoneStateListener
* @return flag boolean if NR is available
*/
private boolean isNrAvailable(ServiceState serviceState ){
String stateStr = serviceState.toString();
return stateStr.contains("nrState=CONNECTED") || stateStr.contains("isNrAvailable = true");
}
}
49 changes: 35 additions & 14 deletions src/ios/CDVConnection.m
Original file line number Diff line number Diff line change
Expand Up @@ -60,28 +60,39 @@ - (NSString*)w3cConnectionTypeFor:(CDVReachability*)reachability
} else {
if ([[[UIDevice currentDevice] systemVersion] compare:@"7.0" options:NSNumericSearch] != NSOrderedAscending) {
CTTelephonyNetworkInfo *telephonyInfo = [CTTelephonyNetworkInfo new];
if ([telephonyInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyGPRS]) {
NSString *currentRadioAccessTechnology = radioAccessNameIn(telephonyInfo);
if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyGPRS]) {
return @"2g";
} else if ([telephonyInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyEdge]) {
} else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyEdge]) {
return @"2g";
} else if ([telephonyInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyWCDMA]) {
} else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyWCDMA]) {
return @"3g";
} else if ([telephonyInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyHSDPA]) {
} else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyHSDPA]) {
return @"3g";
} else if ([telephonyInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyHSUPA]) {
} else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyHSUPA]) {
return @"3g";
} else if ([telephonyInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMA1x]) {
} else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMA1x]) {
return @"3g";
} else if ([telephonyInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORev0]) {
} else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORev0]) {
return @"3g";
} else if ([telephonyInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevA]) {
} else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevA]) {
return @"3g";
} else if ([telephonyInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevB]) {
} else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyCDMAEVDORevB]) {
return @"3g";
} else if ([telephonyInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyeHRPD]) {
} else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyeHRPD]) {
return @"3g";
} else if ([telephonyInfo.currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyLTE]) {
} else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyLTE]) {
return @"4g";
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_14_1
else if (@available(iOS 14.1, *)) {
if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyNRNSA]) {
Copy link
Contributor

Choose a reason for hiding this comment

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

the preprocessor macro doesn't appear to be working as intended here cause iOS 13 tests is failing on this line due to CTRadioAccessTechnologyNRNSA not being available.

/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/tmp-3401-5V69QdTKGZQj/platforms/ios/HelloCordova/Plugins/cordova-plugin-network-information/CDVConnection.m:89:76: error: use of undeclared identifier 'CTRadioAccessTechnologyNRNSA'
                        if ([currentRadioAccessTechnology  isEqualToString:CTRadioAccessTechnologyNRNSA]) {
                                                                           ^

Copy link
Author

@ZumelzuR ZumelzuR Dec 22, 2022

Choose a reason for hiding this comment

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

@breautek this error not make much sense for me, I mean is in a block of code that if the version is iOS14 will try to access.

Also I read this error is related with the xcode

dcloudio/native-docs#30
https://stackoverflow.com/questions/71585983/use-of-undeclared-identifier-ctradioaccesstechnologynr

Any suggestions? I have the last version of xcode and I will try to run it in iOS 13 simulator and check if I can reproduce

return @"5g";
} else if ([currentRadioAccessTechnology isEqualToString:CTRadioAccessTechnologyNR]) {
return @"5g";
}
}
#endif
}
Comment on lines +94 to 96
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is also causing a syntax error...

var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/tmp-3401-5V69QdTKGZQj/platforms/ios/HelloCordova/Plugins/cordova-plugin-network-information/CDVConnection.m:113:1: error: extraneous closing brace ('}')
}

}
return @"cellular";
Expand All @@ -104,9 +115,10 @@ - (NSString*)w3cConnectionTypeFor:(CDVReachability*)reachability
- (BOOL)isCellularConnection:(NSString*)theConnectionType
{
return [theConnectionType isEqualToString:@"2g"] ||
[theConnectionType isEqualToString:@"3g"] ||
[theConnectionType isEqualToString:@"4g"] ||
[theConnectionType isEqualToString:@"cellular"];
[theConnectionType isEqualToString:@"3g"] ||
[theConnectionType isEqualToString:@"4g"] ||
[theConnectionType isEqualToString:@"5g"] ||
[theConnectionType isEqualToString:@"cellular"];
}

- (void)updateReachability:(CDVReachability*)reachability
Expand Down Expand Up @@ -159,4 +171,13 @@ - (void)pluginInitialize
}
}

static NSString *radioAccessNameIn(CTTelephonyNetworkInfo *networkInfo) {
if (@available(iOS 13.0, *)) {
if (networkInfo.currentRadioAccessTechnology == nil && networkInfo.dataServiceIdentifier) {
return [networkInfo.serviceCurrentRadioAccessTechnology objectForKey:networkInfo.dataServiceIdentifier];
}
}
return networkInfo.currentRadioAccessTechnology;
}

@end
2 changes: 2 additions & 0 deletions tests/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ exports.defineAutoTests = function () {
cellular: 1,
'3g': 1,
'4g': 1,
'5g': 1,
none: 1
};
expect(validValues[navigator.connection.type]).toBe(1);
Expand All @@ -49,6 +50,7 @@ exports.defineAutoTests = function () {
expect(Connection.CELL_2G).toBe('2g');
expect(Connection.CELL_3G).toBe('3g');
expect(Connection.CELL_4G).toBe('4g');
expect(Connection.CELL_5G).toBe('5g');
expect(Connection.NONE).toBe('none');
expect(Connection.CELL).toBe('cellular');
});
Expand Down
4 changes: 3 additions & 1 deletion types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ interface Connection {
* Connection.CELL_2G
* Connection.CELL_3G
* Connection.CELL_4G
* Connection.CELL_5G
* Connection.CELL
* Connection.NONE
*/
Expand All @@ -57,6 +58,7 @@ declare var Connection: {
CELL_2G: string;
CELL_3G: string;
CELL_4G: string;
CELL_5G: string;
CELL: string;
NONE: string;
}
}
1 change: 1 addition & 0 deletions www/Connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ module.exports = {
CELL_2G: '2g',
CELL_3G: '3g',
CELL_4G: '4g',
CELL_5G: '5g',
CELL: 'cellular',
NONE: 'none'
};