Get mobile data usage in Android 10 - android

I'm trying to make a network usage monitor app, which shows mobile data usage history to the user. For this I'm using Usage access to get accurate data usage stats from NetworkStatsManager. But this no longer works in Android 10.
I'm using NetworkStatsManager.querySummaryForDevice which requires subscriber Id, which earlier I was able to obtain using TelephonyManager.getSubscriberId.
But the getSubscriberId is now not working in Android 10 as it requires READ_PRIVILEGED_PHONE_STATE which third-party apps cannot have.
Any ideas on how to make it work? I understand the restrictions for getting subscriber Id, but I don't really care about the subscriber Id as long as I get the mobile data usage, for which I have enough permissions.

Try passing null as subscriber ID in the querySummaryForDevice method .. That worked for me

When calling NetworkStatsManager resolve subscriberId as follows:
use null when running on Android versions 10+ (API Level >= 29) devices
on prior versions of Android (API Level < 29) you should still resolve subscriberId (using TelephonyManager)
Here is a sample code that should help:
public static String getSubscriberId() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
return telephonyManager.getSubscriberId();
} else {
return null;
}
}
Worked for me on Android API Level 29 and Android API Level 26 devices.

There's no way at the moment to get the information you want unless your app is a profile or device owner app. You can just use the TrafficStats but you can't use a query and it resets on reboot.

Related

Android WifiManager not enabling/disabling WiFi state

I have a mobile application that allows users to enable/disable WiFi on click of a button.
However I noticed today that my app is no longer able to change the WiFi status. It was working since before few weeks. I tried to debug it but the following method always returns false.
boolean result = wifiManager.setWifiEnabled(true);
I am testing it on Samsung Galaxy Note 9 and Android 10.
This API is no longer supported when targeting Android 10 or higher.
Starting with Build.VERSION_CODES#Q, applications are not allowed to enable/disable Wi-Fi. Compatibility Note: For applications targeting Build.VERSION_CODES.Q or above, this API will always fail and return false. If apps are targeting an older SDK (Build.VERSION_CODES.P or below), they can continue to use this API.
Instead, you should use the Settings.Panel API to present a system UI allowing users to enable or disable Wi-Fi.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startActivity(Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY))
}

Privacy changes in Android 10 for IMEI

I came to know the privacy changes for Android 10 and I'm quite clear that third-party apps won't be able to get IMEI now.
But one thing from documentation is creating confusion for me.
They state
If your app targets Android 9 (API level 28) or lower, the method returns null or placeholder data if the app has the READ_PHONE_STATE permission. Otherwise, a SecurityException occurs.
which means that on Android devices with API LEVEL 28 or lower, this method returns null or placeholder data, even if the app is having READ_PHONE_STATE permission. Right?
But I have tested this thing on my app targetting API LEVEL 28 and I am still able to get IMEI number with the following.
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
fragment.requestPermissions(new String[]{Manifest.permission.READ_PHONE_STATE}, REQUEST_CODE);
}
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
String deviceId = telephonyManager.getImei();
Shouldn't it send me NULL or placeholder (garbage) data?
any idea about it? or am I misinterpreting it?
You're misinterpreting it. What documentation says, is:
If your application targets Android 9 (API level 28) or lower, then it will return null or placeholder data when running on Android 10 device.
Documentation describes here how it will behave on Android 10 in case you don't target Android 10. It's so applications don't suddenly break in strange ways despite not being updated. It has no effect on Android 9 devices (and on emulators that emulate Android 9 devices, which is probably what you're testing it with when targeting API level 28).

Marshmallow Fingerprint Scanner Hardware Presence

I am looking to get started with the Marshmallow Fingerprint Authentication API. I understand that to ask for permission, I must use the following method:
ContextCompat.checkSelfPermission(getContext(), Manifest.permission.USE_FINGERPRINT);
And I must check if the device is running API level 23 or higher. But before I ask for permission, I would like to check if the device actually has a fingerprint scanner to begin with. I found the following two methods to do this check:
FingerprintManager manager = (FingerprintManager) getSystemService(Context.FINGERPRINT_SERVICE);
manager.isHardwareDetected();
manager.hasEnrolledFingerprints();
But both methods require USE_FINGERPRINT permission to be called at all. Why would I want to ask for permission to use a fingerprint scanner that I do not even know exists? Are there any other methods to find out if a scanner exists? Or is the only way to ask for permission first?
I just found the class FingerprintManagerCompat, which does exactly what you would expect:
A class that coordinates access to the fingerprint hardware.
On platforms before M, this class behaves as there would be no fingerprint hardware available.
The same methods from FingerprintManager in this class do not require USE_FINGERPRINT permission, enabling you to call them before you ask for USE_FINGERPRINT permission.
FingerprintManagerCompat manager = FingerprintManagerCompat.from(mContext);
manager.isHardwareDetected();
manager.hasEnrolledFingerprints();
These methods will also yield the expected false results on pre-Marshmallow devices.
Try hasSystemFeature(PackageManager.FEATURE_FINGERPRINT) on a PackageManager instance (you can get one from calling getPackageManager() on any handy Context).
FingerprintManager class supports Android devices running on API 23 or higher and throws an exception on devices running lower Android versions.
FingerprintManagerCompat class give backward compatibility of isHardwareDetected method in lower Android Version but it always returns false for API 23 or higher
I picked best of both and created this method to check for FingerPrint Sensor hardware support in all Android version.
private boolean isSensorAvialable() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return ActivityCompat.checkSelfPermission(AppContext, Manifest.permission.USE_FINGERPRINT) == PackageManager.PERMISSION_GRANTED &&
AppContext.getSystemService(FingerprintManager.class).isHardwareDetected();
} else {
return FingerprintManagerCompat.from(AppContext).isHardwareDetected();
}
}
#CommonsWare mentioned something important, hasSystemFeature. To be on the safe side, if your using Java, make sure you call hasSystemFeature or check for null FingerprintManager return value when calling getSystermService even on devices running API 23 or higher. For Kotlin, use an optional variable and do a smart cast when calling getSystemService to avoid unpredictable crashes in the wild for devices without the Fingerprint hardware but running API 23 or greater.

Android: How to get SIM-ID of both SIMs in Android?

I want to get unique id for SIM (line1number or simserialnumber...) when SMS is received. It works fine for single SIM. Is it possible for multi SIM?
Multiple SIM support was only added to the standard Android API in Android 5.1 (Lollipop_MR1 - API Level 22) - see here. Devices earlier than that with multiple SIMs used customised versions of Android to support multiple SIMs, so there's no standard way to get the information you want as it will work differently on each device.
If you're targeting API Level 22 and above, you can use SubscriptionManager to get the information about different SIMs.
Yes, You can use the SubscriptionManager to get the subscription information.
Also note that we have a Parcelable class for Subscription Information called SubscriptionInfo that has following method relevant to you:
public int getSimSlotIndex ()
public int getSubscriptionId ()

How to know if the android device supports multi users?

Android 4.2 supports multiple user spaces "on shareable devices such as tablets"(http://developer.android.com/about/versions/android-4.2.html#MultipleUsers). How do I know if a specific device is a "shareable device"?
Can I programmatically check if the device supports multiple users?
There is a hidden API at UserManager.supportsMultipleUsers(). You can access this using the following method which uses reflection, though this technique is not normally recommended because the API could change in a later release.
public static boolean supportsMultipleUsers() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
// return UserManager.supportsMultipleUsers();
return (Boolean(UserManager.class.getDeclaredMethod("supportsMultipleUsers").invoke(null));
}
catch (Exception e) {}
return false;
}
If it is enough for you to check if multiple users accounts have been created on the device, you can use UserManager.getUserCount() (after ensuring the SDK version is > 16).
I don't know if it's possible to distinguish if multiple users are theoretically possible, but only one has been used so far from no multi-user support at all.
EDIT: This solution does actually not work, it seems it requires a system-level permission. See here for details UserManager getUserCount() (Jelly Bean)
You can check the Android version with the following code:
int oSversion = Integer.valueOf(android.os.Build.VERSION.SDK_INT);
if (osVersion > 16) {
// This phone supports multi-user
}

Categories

Resources