I have written a simple Statment like this:
val installer = context.packageManager.getInstallerPackageName(context.packageName)
but it's now deprecated as shown in the picture:
Is there any alternative way available to get the package name of the app that has installed your app?
Here's how you can use the new one:
fun getInstallerPackageName(context: Context, packageName: String): String? {
kotlin.runCatching {
if (VERSION.SDK_INT >= VERSION_CODES.R)
return context.packageManager.getInstallSourceInfo(packageName).installingPackageName
#Suppress("DEPRECATION")
return context.packageManager.getInstallerPackageName(packageName)
}
return null
}
Related
I want to use intent method for get uri from another activity, but intent.getParcelableExtra is deprecated.if I use
if (SDK_INT >= 33) {
intent.getParcelableExtra("EXTRA_URI", Uri::class.java).let { ueray ->
timeLineView.post({
if (ueray != null) {
setBitmap(ueray)
videoView.setVideoURI(ueray)
}
})
}
}
else {
#Suppress("DEPRECATION")
intent.getParcelableExtra<Uri>("EXTRA_URI").let { ueray ->
timeLineView.post({
if (ueray != null) {
setBitmap(ueray)
videoView.setVideoURI(ueray)
}
})
}
}
this code can google play reject my app? because when in remove (SDK_INT >= 33) statement it shows
Call requires API level 33 (current min is 21): android.content.Intent#getParcelableExtra. Thanks in advance
No, Google will not reject your app if you use deprecated method, especially when using it is a necessity as you have no other choice than to use it on SDK's < 33.
My app uses deprecated methods on lower SDK's when it is an only possibility and the app is fine and accessible on the Google Play Store:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val vibrationEffect = VibrationEffect.createWaveform(
longArrayOf(1000, 1000),
intArrayOf(255, 0),
0
)
vibrator.vibrate(vibrationEffect, vibrationAudioAttributes)
} else {
// deprecated but working on lower SDK's
vibrator.vibrate(longArrayOf(0, 1000, 1000), 0, vibrationAudioAttributes)
}
These are extension functions for Intent and they are backward compatible:
#Suppress("DEPRECATION")
inline fun <reified P : Parcelable> Intent.getParcelable(key: String): P? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getParcelableExtra(key, P::class.java)
} else {
getParcelableExtra(key)
}
}
#Suppress("DEPRECATION")
inline fun <reified P : Parcelable> Intent.getParcelableArrayList(key: String): ArrayList<P>? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getParcelableArrayListExtra(key, P::class.java)
} else {
getParcelableArrayListExtra(key)
}
}
#Suppress("DEPRECATION")
inline fun <reified P : Parcelable> Bundle.getParcelableValue(key: String): P? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getParcelable(key, P::class.java)
} else {
getParcelable(key)
}
}
#Suppress("DEPRECATION")
inline fun <reified P : Parcelable> Bundle.getParcelableArrayListValue(key: String): ArrayList<P>? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getParcelableArrayList(key, P::class.java)
} else {
getParcelableArrayList(key)
}
}
Instead of the uri put uri.toString() as an extra string.
Quite simple.
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.
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")
}
I created a helper function to check the remaining space of any given directory.
#RequiresApi(Build.VERSION_CODES.O)
fun Context.hasFreeSpace(directory: File, requiredStorageSpace: Long): Boolean{
return try {
val storageManager = getSystemService<StorageManager>()
val directoryUUID = storageManager!!.getUuidForPath(directory)
val availableBytes = storageManager.getAllocatableBytes(directoryUUID)
availableBytes > requiredStorageSpace
}catch (e: Exception){
e.printStackTrace()
false
}
}
Follow this link actually.
https://developer.android.com/training/data-storage/app-specific#query-free-space
The problem is I get storageManager!!.getUuidForPath and storageManager.getAllocatableBytes both require for API >= 26.
I did google around but not thing came back on how to get the directory's UUID on API < 26.
Does anyone have any idea how to achieve that?
Thanks
Well, I guess I need a different approach. As I googled, UUID required was added when Android O was released. So basically, no such thing gets directory UUID exits before O. This is my helper function now.
#SuppressLint("NewApi")
fun Context.hasFreeSpace(directory: File, requiredStorageSpace: Long): Boolean {
return try {
val api = Build.VERSION.SDK_INT
val availableBytes = when {
api >= Build.VERSION_CODES.O -> {
val storageManager = getSystemService<StorageManager>()
val directoryUUID = storageManager!!.getUuidForPath(directory)
storageManager.getAllocatableBytes(directoryUUID)
}
else -> {
val stat = StatFs(directory.path)
stat.availableBlocksLong * stat.blockSizeLong
}
}
availableBytes > requiredStorageSpace
} catch (e: Exception) {
e.printStackTrace()
false
}
}
I am writing a custom android lint to help to check if the private attributes match naming convention.
I used the test cases to verify my implementation. I used a method called isPrivateOrParameterInPrivateMethod() to check if it is private or not but it seems return true everytime I run it.
And I cannot find any documentation about this method (org.jetbrains.kotlin.asJava.classesisPrivateOrParameterInPrivateMethod). If I used it incorrectly, I would like to know.
Appreciate any comment or advice
class PrivateVariableMPrefixDetector : Detector(), Detector.UastScanner {
override fun getApplicableUastTypes() = listOf<Class<out UElement>>(UVariable::class.java)
override fun createUastHandler(context: JavaContext) =
NamingPatternHandler(context)
class NamingPatternHandler(private val context: JavaContext) : UElementHandler() {
override fun visitVariable(node: UVariable) {
node.takeIf { it.isPrivateOrParameterInPrivateMethod() }
?.takeUnless { node.name?.first()?.equals('m') ?: false }
?.run {
process(node, node)
}
}
private fun process(scope: UElement, declaration: PsiNamedElement) {
context.report(
ISSUE_PRIVATE_VAR_PREFIX_WITH_M,
scope,
context.getNameLocation(scope),
"${declaration.name} is not named with prefix m"
)
}
}
}
Test Case
#Test
fun should_not_warn_when_public_variable_is_not_stated_with_m_prefix() {
TestLintTask.lint()
.files(
TestFiles.kt(
"""
class Foo {
val binding
}
"""
).indented()
)
.issues(ISSUE_PRIVATE_VAR_PREFIX_WITH_M)
.run()
.expectClean()
}
Updated on 13/12/2020
There is a class JavaEvaluator inside the JavaContext, and I found some useful method to check the explicit modifier for the variable which suits my cases
class MyHandler(private val context: JavaContext) : UElementHandler() {
override fun visitField(node: UField) {
val isConstant = node.isFinal && node.isStatic
val isEnumConstant = node is UEnumConstant
if (!isConstant && !isEnumConstant) {
node.takeIf {
context.evaluator.hasModifiers(node, KtTokens.PRIVATE_KEYWORD)
}?.run {
process(node, node)
}
}
}
}
Outdated
After putting an effort on it, I found the following solution works. Although I still dun quite understand the meaning of node.sourcePsi, i will make it work first. Appreciate any advice or suggestion
node.takeIf { node.sourcePsi?.text?.startsWith("private") ?: false }
?.takeUnless { node.name.first() == 'm' && node.name.getOrNull(1)?.isUpperCase() ?: false }
?.run {
process(node, node)
}