The code I want to use:
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
There is FLAG_SHOW_WHEN_LOCKED that is deprecated in the API 27 and its alternative setShowWhenLocked added in the API 27
How should I use it properly if the minSdk in my project is 21 and the targetSdk is 33?
I get the warning is deprecated. Deprecated in Java
Even if I handle it this way:
if(Build.VERSION.SDK_INT >= 27) {
setShowWhenLocked(true)
setTurnScreenOn(true)
} else {
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
}
I still get the warning. What is the right way to support both old and new API?
TLDR
1.Use different code for different API versions.
2.Ignore/surpress this warning if you properly proccess all the API versions that your app is created for
3.If there is a new alternative that works for all the API levels - use it
Instruction
Use Build.VERSION.SDK_INT in the condition to behave accordingly to the SDK_INT
Use setshowwhenlocked if SDK_INT>=27 and FLAG_SHOW_WHEN_LOCKED if SDK_INT<27
Surpress the warning
Example with the FLAG_SHOW_WHEN_LOCKED/setShowWhenLocked
if(Build.VERSION.SDK_INT >= 27) {
setShowWhenLocked(true)
setTurnScreenOn(true)
} else {
#Suppress("DEPRECATION")
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
}
But why do we have to surpsess the warning?
The warning exists only because #Deprecated APIs do not have any metadata that would indicate which SDK they were deprecated in. as you can see in this issue.
We can surpress the error because we have properly processed both old api (5-27) and new api (27>)
Warning
Do not surpress these warnings if the code is not properly processed by using if conditions where the right API is used.
Example how you must not do
#Suppress("DEPRECATION")
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
Your minSdk is 21 and targetSdk is 33
This code will work on devices with 5-27 API (Android 5 - Android 8.1) but will not work on new devices. You must properly handle both conditions.
Example with the Vibrator
The old way to get the vibrator
context.getSystemService(VIBRATOR_SERVICE) as Vibrator
The new way to get the vibrator
val vibrator = if (Build.VERSION.SDK_INT >= 31) {
val vibratorManager =
context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager
vibratorManager.defaultVibrator
} else {
#Suppress("DEPRECATION")
context.getSystemService(VIBRATOR_SERVICE) as Vibrator
}
Will show you the warning `'VIBRATOR_SERVICE: String' is deprecated. Deprecated in Java`. Go to the [documentation](https://developer.android.com/reference/kotlin/android/content/Context#vibrator_service) and see that this constant can be used in the API 1-31 so we must. And in both IDE and documentation there is the info about the alternative: `Deprecated: Use android.os.VibratorManager to retrieve the default system vibrator.`. As you can see the [VibrationManager](https://developer.android.com/reference/kotlin/android/os/VibratorManager) is added in the API 31 therefore we must write the different code for different sdk versions
If an alternative is backwards compatible
If an alternative is backwards compatible you can just use it instead of the old way
Example
If you inherit AppCompatActivity in your activity:
class SaveMyLifeActivity : AppCompatActivity()
You can meet the warning startActivityForResult(Intent!, Int): Unit' is deprecated. Deprecated in Java if you call startActivityForResult:
val intent = Intent(this, SaveMyLifeActivity::class.java)
startActivityForResult(intent, 0)
You can press Alt+Q (Default keybind) to see the Context info(it is called this way in the AndroidStudio is you check your keymap) or use the website do see the documentation
Take a look to the words that this method is deprecated and you must use registerForActivityResult instead. This method can be called in any version right now, there are no Added/Deprecated "section" in the documentation.
Question: How have you found this documentation? I google AppCombatActivity startActivityForResult and come to this documentation. There is no word about startActivityForResult.
Answer: Open the context info about this method in the IDE (Alt+Q) and look at the bottom of the Context info . There is a class name where this method is located in (ComponentActivity). You have to google ComponentActivity startActivityForResult instead of AppCombatActivity startActivityForResult
Related
I am getting a strange behavior in Android Studio with API33. In the following code,
Intent chooser = Intent.createChooser(sharingIntent, filename);
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(chooser, android.content.pm.PackageManager.MATCH_DEFAULT_ONLY);
I am getting queryIntentActivities(Intent,int) in PackageManager has been deprecated.
In the docs, it says: This method was deprecated in API level 33. Use queryIntentActivities(android.content.Intent, android.content.pm.PackageManager.ResolveInfoFlags) instead.
I tried changing Intent with android.content.Intent, but get the same problem. PackageManager.MATCH_DEFAULT_ONLY is one of the possible flag values, so I do not understand what this error is trying to tell me...
Your current call is:
queryIntentActivities(chooser, android.content.pm.PackageManager.MATCH_DEFAULT_ONLY)
Here, chooser is an Intent, and MATCH_DEFAULT_ONLY is an int.
That matches the deprecated queryIntentActivities() version.
On API Level 33 and higher devices, Google would like you to use the queryIntentActivities() version that takes a ResolveInfoFlags as the second parameter, instead of an int. You would use ResolveInfoFlags.of() to wrap MATCH_DEFAULT_ONLY into a ResolveInfoFlags object.
That method will not be available on API Level 32 and older devices, so your choices are:
Stick with the int one, despite the deprecation, or
Use Build.VERSION.SDK_INT to determine the API level and call the desired version of queryIntentActivities() based on the API level of the device
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.packageManager.queryIntentActivities(
Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER),
PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong())
)
} else {
context.packageManager.queryIntentActivities(
Intent(Intent.ACTION_MAIN, null).addCategory(Intent.CATEGORY_LAUNCHER),
PackageManager.GET_META_DATA
)
}
This means you need to pass InfoFlag as second parameter and not an int. Here you can find list of the flags and from there you can check what each one is for so you can use it for your example
So the solution would look something like
queryIntentActivities(chooser, android.content.pm.PackageManager.MATCH_DEFAULT_ONLY)
I think we can cast PackageManager.MATCH_DEFAULT_ONLY into long.
Something like this:
queryIntentActivities(intent, PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY.toLong()))
I want to set password policy on screen lock and now I use setPasswordQuality(ComponentName admin, int quality) in DevicePolicyManager but this method is deprecated on API 31 and they add new method(setRequiredPasswordComplexity(passwordComplexity : Int)).
I can use this method in API < 31?
If I can,how should I use it?
https://developer.android.com/reference/android/app/admin/DevicePolicyManager#setRequiredPasswordComplexity(int)
As the documentation already states the method was added in API 31 and since there is no backward compatibility library for this so this functionality can only be used on devices with api 31 or above
I think your problem might solve here. You can check the build version by
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
// Do something for version 31 and above versions
} else{
// do something for phones running an SDK before 31
}
From android 11 setUserAuthenticationValidityDurationSeconds are deprecated in favor of setUserAuthenticationParameters inside KeyGenParameterSpec.Builder but seams there is any support for previous versions.
so, what are best the solution ?
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(...)
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R)
builder.setUserAuthenticationParameters(timeout, KeyProperties.AUTH_DEVICE_CREDENTIAL | KeyProperties.AUTH_BIOMETRIC_STRONG);
else
//noinspection deprecation
builder.setUserAuthenticationValidityDurationSeconds(timeout);
this one?
You don't need to migrate the actual keys, when you are ready to support Android 11 you can just switch to something like this, (don't forget to set compileSdkVersion 30 for the new APIs)
val timeout = 30 //seconds
val builder = KeyGenParameterSpec.Builder(...)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
builder.setUserAuthenticationParameters(timeout,
KeyProperties.AUTH_DEVICE_CREDENTIAL
or KeyProperties.AUTH_BIOMETRIC_STRONG
)
} else {
builder.setUserAuthenticationValidityDurationSeconds(timeout)
}
You can do this because internally setUserAuthenticationValidityDurationSeconds is doing the same thing. The only exception is if you are calling setUserAuthenticationValidityDurationSeconds with -1 as the timeout. In this case the equivalent with the new API is builder.setUserAuthenticationParameters(0, KeyProperties.AUTH_BIOMETRIC_STRONG).
You can check here the source code for both cases.
PS: The code above is minAPI 24, you need to wrap the code above in more build checks if you are at a lower API level.
I try to use constructor of AlertDialog.Builder which gets a context and a theme:
AlertDialog.Builder b = new AlertDialog.Builder(this, 0);
It shows an error on my Eclipse (marking the "Builder" type): "Call requires API level 11 (current min is 7)".
When I use the constructor which gets only the context (without theme), it doesn't show this error.
I want to be able to deploy my app also on old androids (such as version 2.1 etc.). Is there any convenient way for me to use the simple constructor of AlertDialog.Builder when it's an old version, and to use the more complicated constructor when it's API 11 and above?
Just out of curiosity, how does the compiler know what API version is needed for the use of a certain method?
You may use the const Build.VERSION.SDK_INT on an if clause, to check if your API level is above or below the required level (You will probably have to add an annotation to suppress the API level warning / error from that method / class).
Android Lint does that for you. It checks which methods and ctors are allowed on a certain API level.
Example:
if(Build.VERSION.SDK_INT >= 11) {
//API level 11 and above ctor here
} else {
//Lower than API level 11 code here
}
For instance, this code:
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD) {
myCalendarView.setOnDateChangeListener(
new OnDateChangeListener() {
#Override
public void onSelectedDayChange(CalendarView view, int year, int month, int dayOfMonth) {
Toast.makeText
(
getApplicationContext(), ""+dayOfMonth, 0
).show();
}
}
);
}
Gives error:
Description Resource Path Location Type Call requires API level 11
(current min is 8):
android.widget.CalendarView#setOnDateChangeListener example.java /example/src/com/example/example line
20 Android Lint Problem
I understand why I get this error compile-time. But is there any way to mark a source Java class to only be used on certain API level-11? Or surround code blocks with a define/similar so the code is late-bound/jitted only on devices above API level-11? What is the best solution to achieve what I want? (Which is to provide an activity with CalendarView on devices capabile of it.)
I'm not sure if this is going to solve your issue,
but what you are using to check version is not working under API 9
(and you are supporting since API 8).
You should use:
if (Build.VERSION.SDK_INT > 9) {
Or as problematic function is API 11, check for "SDK_INT>10"
Then for lint errors on eclipse, do as people comment, disable lint errors or add the #SuppressLint("NewAPi") or the target to that function to 11.
For anyone stumbling upon this much later, conditionally executing code based on the API version at runtime is currently a valid way of supporting different platform versions.
See: https://developer.android.com/training/basics/supporting-devices/platforms#version-codes
Where it says:
Android provides a unique code for each platform version in the Build
constants class. Use these codes within your app to build conditions
that ensure the code that depends on higher API levels is executed
only when those APIs are available on the system.
And gives examples:-
Java:
private void setUpActionBar() {
// Make sure we're running on Honeycomb or higher to use ActionBar APIs
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
Kotlin:
private fun setUpActionBar() {
// Make sure we're running on Honeycomb or higher to use ActionBar APIs
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
actionBar.setDisplayHomeAsUpEnabled(true)
}
}