How to get BATTERY_PROPERTY_CHARGE_COUNTER on api 21 Android - android

Why does getIntProperty return zero on the api device 21
val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val BatteryCapacity = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)

Related

Get app usage from yesterday with UsageStatsManager

I tried to get the app usage from previous day 0 o'clock to today 0 o'clock.
Here is my Code:
val midnight = LocalTime.MIDNIGHT
val today = LocalDate.now()
val todayMidnight = LocalDateTime.of(today, midnight)
val todayMidnightMillis = toMillis(todayMidnight)
val yesterdayMidnightMillis = toMillis(todayMidnight.minusDays(1))
val usageStatsManager = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
val queryUsageStatsMap = usageStatsManager.queryAndAggregateUsageStats(yesterdayMidnightMillis, todayMidnightMillis)
val appInfoMap = getNonSystemAppsList()
for (packageName in appInfoMap) {
val usageStats = queryUsageStatsMap.get(packageName.key)
if (usageStats != null) {
if (usageStats.totalTimeVisible > 0) {
val name = usageStats.packageName
val hours = TimeUnit.MILLISECONDS.toHours(usageStats.totalTimeVisible) % 24
val minutes = TimeUnit.MILLISECONDS.toMinutes(usageStats.totalTimeVisible) % 60
val seconds = TimeUnit.MILLISECONDS.toSeconds(usageStats.totalTimeVisible) % 60
//insert into database
}
}
}
private fun toMillis(dateTime: LocalDateTime): Long {
return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()
}
For example:
yesterdayMidnightMillis = 1673996400000 (18.01.2023-00:00)
todayMidnightMillis = 1674082800000 (19.01.2023-00:00)
For example, when I call this method(19.01.2023-15:00), the method gives me an app usage of 10 min. If I wait a minute and call the method again, the method gives me an app usage of 11 min.
Since I am not in the specified time interval during this time, the app usage must not increase.

Android 13 (SDK 33): PackageManager.getPackageInfo(String, int) deprecated. what is the alternative?

Starting from API level 33 the getPackageInfo(String, int) method of PackageManager class is deprecated. Documentation suggests to use getPackageInfo(String, PackageInfoFlags) instead. But that function is only available from API level 33.
My current code:
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
Is this how it should be now?
val pInfo = context.getPackageInfo()
#Suppress("DEPRECATION")
fun Context.getPackageInfo(): PackageInfo {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
packageManager.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0))
} else {
packageManager.getPackageInfo(packageName, 0)
}
}
If you are using Kotlin, you can add extension function to your project:
fun PackageManager.getPackageInfoCompat(packageName: String, flags: Int = 0): PackageInfo =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(flags.toLong()))
} else {
#Suppress("DEPRECATION") getPackageInfo(packageName, flags)
}
and after just call packageManager.getPackageInfoCompat(packageName) or add another flag, if you need.
Is this how it should be now?
Yes, though I've gotten out of the practice of using TIRAMISU in favor of the actual underlying Int.
Ideally, Google would add stuff to PackageManagerCompat for these changes, and perhaps they will now that Android 13 is starting to ship to users.

Android getParcelableExtra deprecated

I am passing data via intent with Parcelable and receiving using getParcelableExtra . However getParcelableExtra seems to be deprecated, How do I fix the deprecation warning in this code? Alternatively, are there any other options for doing this? . I am using compileSdkVersion 33.
Code snippet:
var data = intent.getParcelableExtra("data")
Here are two extension methods that I use for Bundle & Intent:
inline fun <reified T : Parcelable> Intent.parcelable(key: String): T? = when {
SDK_INT >= 33 -> getParcelableExtra(key, T::class.java)
else -> #Suppress("DEPRECATION") getParcelableExtra(key) as? T
}
inline fun <reified T : Parcelable> Bundle.parcelable(key: String): T? = when {
SDK_INT >= 33 -> getParcelable(key, T::class.java)
else -> #Suppress("DEPRECATION") getParcelable(key) as? T
}
I also requested this to be added to the support library
And if you need the ArrayList support there is:
inline fun <reified T : Parcelable> Bundle.parcelableArrayList(key: String): ArrayList<T>? = when {
SDK_INT >= 33 -> getParcelableArrayList(key, T::class.java)
else -> #Suppress("DEPRECATION") getParcelableArrayList(key)
}
inline fun <reified T : Parcelable> Intent.parcelableArrayList(key: String): ArrayList<T>? = when {
SDK_INT >= 33 -> getParcelableArrayListExtra(key, T::class.java)
else -> #Suppress("DEPRECATION") getParcelableArrayListExtra(key)
}
Now we need to use getParcelableExtra() with the type-safer class added to API 33
SAMPLE CODE For kotlin
val userData = if (VERSION.SDK_INT >= 33) {
intent.getParcelableExtra("DATA", User::class.java)
} else {
intent.getParcelableExtra<User>("DATA")
}
SAMPLE CODE For JAVA
if (android.os.Build.VERSION.SDK_INT >= 33) {
user = getIntent().getParcelableExtra("data", User.class);
} else {
user = getIntent().getParcelableExtra("data");
}
For example, in Java:
UsbDevice device;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S_V2) { // TIRAMISU onwards
device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE, UsbDevice.class);
} else {
device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
}
This still requires #SuppressWarnings({"deprecation", "RedundantSuppression"}).
As described in the official documentation, getParcelableExtra was deprecated in API level 33.
So check if the API LEVEL is >= 33 or change the method,
...
if (Build.VERSION.SDK_INT >= 33) {
data = intent.getParcelableExtra (String name, Class<T> clazz)
}else{
data = intent.getParcelableExtra("data")
}

How to get the phone number and SIM card slot for the current device, on the callback of onCallAdded?

Background
I'm working on an app that implements InCallService, so it can handle phone calls
The problem
On devices with multi-SIM, I need to show information of which SIM and associated phone number is used (of the current device).
Thing is, I can't find where to get this information.
What I've found
Given that I reach a function like onCallAdded, I get an instance of Call class, so I need to associate something I get from there, to a sim slot and phone number.
Using call.getDetails().getHandle() , I can get a Uri consisting only the phone number of the other person that called (who called the current user, or who the current user has called).
I can iterate over all SIM cards, but can't find what I can use to map between them and the current call:
final TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
final SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
for (final SubscriptionInfo subscriptionInfo : subscriptionManager.getActiveSubscriptionInfoList()) {
final TelephonyManager subscriptionId = telephonyManager.createForSubscriptionId(subscriptionInfo.getSubscriptionId());
}
There was an old code that doesn't work anymore that uses call.getDetails().getAccountHandle().getId() and SubscriptionManager.from(context)getActiveSubscriptionInfoList().getActiveSubscriptionInfoList() .
I think I can use telephonyManager.getSubscriptionId(callDetails.getAccountHandle()) , but it requires API 30, which is quite new...
The questions
Given a phone call that I get from this callback (and probably others), how can I get the associated SIM slot and phone number of it?
I prefer to know how to do it for as wide range of Android versions as possible, because InCallService is from API 23... It should be possible before API 30, right?
Use call.getDetails().getAccountHandle() to get PhoneAccountHandle.
Then use TelecomManager.getPhoneAccount() to get PhoneAccount instance.
Permission Manifest.permission.READ_PHONE_NUMBERS is needed for applications targeting API level 31+.
Disclaimer: I am no Android expert, so please do validate my thoughts.
EDIT: So solution for both before API 30 and from API 30 could be as such:
#RequiresApi(Build.VERSION_CODES.M)
fun handleCall(context: Context, call: Call) {
var foundAndSetSimDetails = false
val callDetailsAccountHandle = callDetails.accountHandle
val subscriptionManager = context
.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
val telephonyManager =
context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
val telecomManager =
context.getSystemService(Context.TELECOM_SERVICE) as TelecomManager
val hasReadPhoneStatePermission =
ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == android.content.pm.PackageManager.PERMISSION_GRANTED
val phoneAccount = telecomManager.getPhoneAccount(callDetailsAccountHandle)
//TODO when targeting API 31, we might need to check for a new permission here, of READ_PHONE_NUMBERS
//find SIM by phone account
if (!foundAndSetSimDetails && phoneAccount != null && hasReadPhoneStatePermission) {
val callCapablePhoneAccounts = telecomManager.callCapablePhoneAccounts
run {
callCapablePhoneAccounts?.forEachIndexed { index, phoneAccountHandle ->
if (phoneAccountHandle != callDetailsAccountHandle)
return#forEachIndexed
if (!phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION))
return#run
//found the sim card index
simName = phoneAccount.label?.toString().orEmpty()
simIndex = index + 1
foundAndSetSimDetails = true
return#run
}
}
}
//find SIM by subscription ID
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && hasReadPhoneStatePermission) {
try {
val callSubscriptionId: Int =
telephonyManager.getSubscriptionId(callDetailsAccountHandle!!)
for (subscriptionInfo: SubscriptionInfo in subscriptionManager.activeSubscriptionInfoList) {
val activeSubscriptionId: Int = subscriptionInfo.subscriptionId
if (activeSubscriptionId == callSubscriptionId) {
setSimDetails(telephonyManager, subscriptionInfo)
foundAndSetSimDetails = true
break
}
}
} catch (e: Throwable) {
e.printStackTrace()
}
}
//find SIM by phone number
if (!foundAndSetSimDetails && hasReadPhoneStatePermission) {
try {
val simPhoneNumber: String? = phoneAccount?.address?.schemeSpecificPart
if (!simPhoneNumber.isNullOrBlank()) {
for (subscriptionInfo in subscriptionManager.activeSubscriptionInfoList) {
if (simPhoneNumber == subscriptionInfo.number) {
setSimDetails(telephonyManager, subscriptionInfo)
foundAndSetSimDetails = true
break
}
}
if (!foundAndSetSimDetails)
}
} catch (e: Throwable) {
e.printStackTrace()
}
}
private fun setSimDetails(telephonyManager: TelephonyManager, subscriptionInfo: SubscriptionInfo) {
var foundSimName: String? = null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val telephonyManagerForSubscriptionId =
telephonyManager.createForSubscriptionId(subscriptionInfo.subscriptionId)
foundSimName = telephonyManagerForSubscriptionId.simOperatorName
}
if (foundSimName.isNullOrBlank())
foundSimName = subscriptionInfo.carrierName?.toString()
simName = if (foundSimName.isNullOrBlank())
""
else foundSimName
simIndex = subscriptionInfo.simSlotIndex + 1
}

Check internet connection with target sdk 29 and without deprecated methods

I have the
compileSdkVersion 29
and
targetSdkVersion 29
in my android app. And to check if there is a connection I use the next code:
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
return connectivityManager?.activeNetworkInfo?.isConnected ?: false
But with my targetSdk the activeNetworkInfo is deprecated. How can I check the connection status without deprecated methods and variables?
You can do it as below:
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
val network = connectivityManager.activeNetwork
val capabilities = connectivityManager.getNetworkCapabilities(network)
return capabilities != null && (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || capabilities.hasTransport(
NetworkCapabilities.TRANSPORT_CELLULAR
))
}
Use ConnectivityManager.NetworkCallback instead, here is the link for documentation

Categories

Resources