I am trying to detect 5G network. I use the telephony manager to get NETWORK_TYPE. Even if I am in 5G network coverage and my phone shows 5G, I do not get NETWORK_TYPE_NR. The NETWORK_TYPE is always 13 i.e. LTE.
The Phones Engineering service mode shows NR related data.
Is there any way to detect NR (Standalone or Non-Standalone) mode?
I also need to get the Cell Information for NR data. I use telephonyManager.getAllCellinfo(), but I never get an instance of cellinfonr.
Any help is appreciated. Thanks
I faced the same problem for a few weeks ago. In my case, I want to detect 5G network on Galaxy S20-5G but the getDataNetworkType() always return 13 NETWORK_TYPE_LTE.
Following by netmonster-core strategy, and here is the code that I extract from them to solve my problem.
public boolean isNRConnected(TelephonyManager telephonyManager) {
try {
Object obj = Class.forName(telephonyManager.getClass().getName())
.getDeclaredMethod("getServiceState", new Class[0]).invoke(telephonyManager, new Object[0]);
// try extracting from string
String serviceState = obj.toString();
boolean is5gActive = serviceState.contains("nrState=CONNECTED") ||
serviceState.contains("nsaState=5") ||
(serviceState.contains("EnDc=true") &&
serviceState.contains("5G Allocated=true"));
if (is5gActive) {
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
Here is full detector class from netmonster-core:
(DetectorLteAdvancedNrServiceState.kt)
Related
Android Q added a new network type, NETWORK_TYPE_NR for 5G which is
not available for Android Pie. Recently released Samsung S10 fully supports 5G. It can show 5G icon on the status bar when it is on the 5G network.
Is it possible for a third-party app to know if Android Pie device on a 5G network or not?
Any help will be appreciated.
The following link is the definition for the new network type. It is not available on the Android Pie branch.
Source code for Pie release
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/pie-release-2/telephony/java/android/telephony/TelephonyManager.java
The latest source code that has NETWORK_TYPE_NR
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/telephony/java/android/telephony/TelephonyManager.java#2375
I believe they backported the code from Q to Pie as the logic for 5G was implemented at the end of last year in Q (alpha).
So when using
TelephonyManager.getNetworkType()
you will likely get
20 (5G)
EDIT
As per comment below: The network type will be 13 so it doesn't solve the thing.
EDIT
Try using reflection
static boolean isNRConnected(TelephonyManager telephonyManager) {
try {
Object obj = Class.forName(telephonyManager.getClass().getName())
.getDeclaredMethod("getServiceState", new Class[0]).invoke(telephonyManager, new Object[0]);
Method[] methods = Class.forName(obj.getClass().getName()).getDeclaredMethods();
for (Method method : methods) {
if (method.getName().equals("getNrStatus") || method.getName().equals("getNrState")) {
method.setAccessible(true);
return ((Integer) method.invoke(obj, new Object[0])).intValue() == 3;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
There is an official documentation to detect 5G on Android 11.
https://developer.android.com/about/versions/11/features/5g#detection
Call TelephonyManager.listen(), passing in LISTEN_DISPLAY_INFO_CHANGED, to determine if the user has a 5G network connection.
as #Hunter suggested you need to use "listen" from telephony manager but if it's api 30+ you need to have READ_PHONE permission granted and listen for LISTEN_DISPLAY_INFO_CHANGED and override onDisplayInfoChanged from PhoneStateListener
(context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager).listen(customPhoneStateListener,PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED)
The listener should be something like this:
private class CustomPhoneStateListener : PhoneStateListener() {
override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) {
super.onDisplayInfoChanged(telephonyDisplayInfo)
when (telephonyDisplayInfo.overrideNetworkType) {
//5G
OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO,
OVERRIDE_NETWORK_TYPE_NR_NSA,
OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE -> setNetworkChange(NETWORK_TYPE_NR)
OVERRIDE_NETWORK_TYPE_LTE_CA -> {
setNetworkChange(19) //LTE+
}
else -> setNetworkChange(telephonyDisplayInfo.networkType)
}
} else {
setNetworkChange(telephonyDisplayInfo.networkType)
}
}
}
Link: https://developer.android.com/about/versions/11/features/5g#detection
Couldn't add this as a comment, but as #Pavel Machala said, looking at the ServiceState class in the AOSP yields the following:
/**
* Get the NR 5G status of the mobile data network.
* #return the NR 5G status.
* #hide
*/
public #NRStatus int getNrStatus() {
final NetworkRegistrationState regState = getNetworkRegistrationState(
NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
if (regState == null) return NetworkRegistrationState.NR_STATUS_NONE;
return regState.getNrStatus();
}
I have extracted the ServiceState.java from SM-G977N firmware and it confirms that they have added
ServiceState.getNrStatus()
5G(NR) is active is if NetworkRegistrationState.NR_STATUS_CONNECTED = 3;
I'm trying to get current route for my input audio by calling AudioRecord.getRoutedDevice(); during recording, but on most Android API23+ devices it returns null (out of 300k various Android devices, only 10% return meaningful info). Even on the same device model (Samsung Galaxy S5, 6.0.1), 70% of devices return null, and 30% return correct info.
I tried to debug this using reflection, and replicated some of the SDK code to step through it - and I can see that inside of AudioRecord.getRoutedDevice(); I do get reasonable response both from native_getRoutedDeviceId() and getAudioManager().getDevices(), but then ids don't match:
#TargetApi(23)
private AudioDeviceInfo getRoutedDevice() {
Object r = (Object)(0);
try {
Method method = _record.getClass().getDeclaredMethod("native_getRoutedDeviceId");
method.setAccessible(true);
r = method.invoke(_record);
} catch (Exception e) {
e.printStackTrace();
}
int deviceId = (int)r; //native_getRoutedDeviceId();
if (deviceId == 0)
return null;
AudioDeviceInfo[] devices =
getAudioManager().getDevices(AudioManager.GET_DEVICES_INPUTS);
for (int i = 0; i < devices.length; i++)
if (devices[i].getId() == deviceId)
return devices[i];
return null;
}
What could I be possibly doing wrong, and is there any other API that I could be using?
Old API like AudioManager.isWiredHeadsetOn() for example doesn't guarantee that audio IO is going through the headset at the moment.
From the docs
Note: The query is only valid if the AudioRecord is currently
recording. If it is not, getRoutedDevice() will return null.
Using TrafficStats i was checking the youtube app data usage.In some devices it is working fine but not with many other devices.
I found that from developer site, These statistics may not be available on all platforms. If the statistics are not supported by this device, UNSUPPORTED will be returned.
So in these case how can I get the device app usage ?
I was using
TrafficStats.getUidRxBytes(packageInfo.uid) + TrafficStats.getUidTxBytes(packageInfo.uid);
this is returning -1 everytime.
We can use NetworkStats.
https://developer.android.com/reference/android/app/usage/NetworkStats.html
Please see a sample repo which I got the clue.
https://github.com/RobertZagorski/NetworkStats
We can see a similar stackoverflow question as well.
Getting mobile data usage history using NetworkStatsManager
Then I needed to modify this logic for some particular devices. In these devices the normal method won't return proper usage values. So I modified is as
/*
getting youtube usage for both mobile and wifi.
*/
public long getYoutubeTotalusage(Context context) {
String subId = getSubscriberId(context, ConnectivityManager.TYPE_MOBILE);
//both mobile and wifi usage is calculating. For mobile usage we need subscriberid. For wifi we can give it as empty string value.
return getYoutubeUsage(ConnectivityManager.TYPE_MOBILE, subId) + getYoutubeUsage(ConnectivityManager.TYPE_WIFI, "");
}
private long getYoutubeUsage(int networkType, String subScriberId) {
NetworkStats networkStatsByApp;
long currentYoutubeUsage = 0L;
try {
networkStatsByApp = networkStatsManager.querySummary(networkType, subScriberId, 0, System.currentTimeMillis());
do {
NetworkStats.Bucket bucket = new NetworkStats.Bucket();
networkStatsByApp.getNextBucket(bucket);
if (bucket.getUid() == packageUid) {
//rajeesh : in some devices this is immediately looping twice and the second iteration is returning correct value. So result returning is moved to the end.
currentYoutubeUsage = (bucket.getRxBytes() + bucket.getTxBytes());
}
} while (networkStatsByApp.hasNextBucket());
} catch (RemoteException e) {
e.printStackTrace();
}
return currentYoutubeUsage;
}
private String getSubscriberId(Context context, int networkType) {
if (ConnectivityManager.TYPE_MOBILE == networkType) {
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
return tm.getSubscriberId();
}
return "";
}
I want to check if an android devices is rooted or not. If device is rooted I dont want my application to show the appropriate message to the user and the application should not work on a rooted device.
I have gone through various links and blogs which have code snipplets to check if device is rooted or not. But I also found multiple developers saying that it is not possible to programmatically check for sure if a device is rooted or no. The code snippets might not give 100% accurate results on all the devices and results might also depend on the tool used for rooting the android device.
Please let me know if there is any way to confirm for sure that the device is rooted or not programmatically.
Thanks,
Sagar
I don't have enough reputation points to comment, so I have to add another answer.
The code in CodeMonkey's post works on most devices, but at least on Nexus 5 with Marshmallow it doesn't, because the which command actually works even on non-rooted devices. But because su doesn't work, it returns a non-zero exit value. This code expects an exception though, so it has to be modified like this:
private static boolean canExecuteCommand(String command) {
try {
int exitValue = Runtime.getRuntime().exec(command).waitFor();
return exitValue == 0;
} catch (Exception e) {
return false;
}
}
Possible duplicate of Stackoverflow.
This one has an answer
Answer on the second link. The guy tested it on about 10 devices and it worked for him.
/**
* Checks if the device is rooted.
*
* #return <code>true</code> if the device is rooted, <code>false</code> otherwise.
*/
public static boolean isRooted() {
// get from build info
String buildTags = android.os.Build.TAGS;
if (buildTags != null && buildTags.contains("test-keys")) {
return true;
}
// check if /system/app/Superuser.apk is present
try {
File file = new File("/system/app/Superuser.apk");
if (file.exists()) {
return true;
}
} catch (Exception e1) {
// ignore
}
// try executing commands
return canExecuteCommand("/system/xbin/which su")
|| canExecuteCommand("/system/bin/which su") || canExecuteCommand("which su");
}
// executes a command on the system
private static boolean canExecuteCommand(String command) {
boolean executedSuccesfully;
try {
Runtime.getRuntime().exec(command);
executedSuccesfully = true;
} catch (Exception e) {
executedSuccesfully = false;
}
return executedSuccesfully;
}
I have an Android phone app that accesses the phone number for registration info like this:
String thisPhoneNumber = "0";
try {
TelephonyManager tMgr=(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
thisPhoneNumber = tMgr.getLine1Number(); }
catch (Exception e) { }
It works fine on the phone. A friend tried it on the tablet (a recent one) and the app crashes. If I comment out the 4 lines of try/catch it works fine so it looks like the crash must be on the getSystemService call.
In a bit of searching stackoverflow, it sounds like code should run on either platform but that's not what I'm seeing.
Shouldn't the try/catch prevent the crash and allow the exception to be handled?
Is there some other way to allow the getSystemService to execute without crashing on the tablet? Or do I have to not make that call on the tablet?
check with if statement check if of the variables in those 2-3 lines are null, and stop executing the code if so, for example
try
{
TelephonyManager tMgr=(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
if(tMgr!=null)
thisPhoneNumber = tMgr.getLine1Number(); }
cath(Exception o)
{}
or you can try to find if the device is a tablet or phone(phone or non phone device)
and then execute two different statements in if code
if(phone) { the code}
or you can have abstract class whit a function find phone number
and do some think like
if(device is phone)
{
apstractClass=new phoneImplementation();
} else
{
apstractClass= new nonPhoneImplementation();if (((TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE)).getLine1Number()
== null)
{
// no phone
} enter code here
}
thisPhoneNumber=apstarctClass.getPhoneNumber()
where phoneImplementation().getPhoneNumber() will have your code, the code from the question and nonPhoneImplementation().getPhoneNumber() will return 0
you can check with this if a device has phone capabilities
if (((TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE)).getLine1Number()
== null)
{
// no phone
}
My opinion is that this will solve your problem:
String thisPhoneNumber = "0";
try
{
if (((TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE)).getLine1Number()
!= null)
{
thisPhoneNumber = tMgr.getLine1Number();
} }
catch(Exception o)
{}