I was messing around with MeasureSpec when I came across this bit of text:
Note: On API level 17 and lower, makeMeasureSpec's implementation was such that the order of arguments did not matter and overflow in either value could impact the resulting MeasureSpec. RelativeLayout was affected by this bug. Apps targeting API levels greater than 17 will get the fixed, more strict behavior.
So that got me wondering: If I build an app for API 14 but I run it on an API 22 device will it fix the bug or will < API 17's bug still exist on the 22 device?
makeMeasureSpec(API 17<) method's implementation is the following:
public static int makeMeasureSpec(int size, int mode) {
if (sUseBrokenMakeMeasureSpec) {
return size + mode;
} else {
return (size & ~MODE_MASK) | (mode & MODE_MASK);
}
}
As you can see it's return value is depending on the value of sUseBrokenMakeMeasureSpec which value is assigned in the View class's constructor:
sUseBrokenMakeMeasureSpec = targetSdkVersion <= JELLY_BEAN_MR1;
So only the app's target will determine the behaviour. By doing it this way a newer system can maintain compatibility with an older app which expets the old behaviour.
Related
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
}
I'm using android Log.isLoggable api in order to determine whether my custom log tag is on and should I log. (I'm setting property using setprop log.tag. on the device).
As far as Docs says, and as I'm familiar with older version, it should return true if the log level in the property is equal or high than the one I'm checking in my code.
This works fine for Lollipop and below (api 22) it's seems that something was changed in Marshmallow, as I encounter inconsistency and buggy behavior, playing with the values of the tag will result sometimes with the wrong value returned from isLogabble(), for instance a concrete scenario I did a check in code :
boolean shouldLog = Log.isLoggable("mytag", Log.DEBUG);
Log.d("debug", "shouldLog = " + shouldLog);
I set log.tag.mytag value to some arbitrary string
launch my app, and see the isLoggable = false, that's OK
then I change log.tag.mytag to VERBOSE
launch my app, isLoggable still false , that's not OK! should be true now
same scenario is not reproducible at Lollipop and didn't encounter any other misbehaviors.
Any suggestions, do I miss something here?
In an Android app, we wish to have an iOS-like horizontal scroll wheel, and we are using HorizontalPicker.
This requires API 17 for calls getTextDirection() and getLayoutDirection().
For getTextDirection, the usage is:
switch (getTextDirection()) {
default:
case TEXT_DIRECTION_FIRST_STRONG:
return (defaultIsRtl ? TextDirectionHeuristicsCompat.FIRSTSTRONG_RTL :
TextDirectionHeuristicsCompat.FIRSTSTRONG_LTR);
case TEXT_DIRECTION_ANY_RTL:
return TextDirectionHeuristicsCompat.ANYRTL_LTR;
case TEXT_DIRECTION_LTR:
return TextDirectionHeuristicsCompat.LTR;
case TEXT_DIRECTION_RTL:
return TextDirectionHeuristicsCompat.RTL;
case TEXT_DIRECTION_LOCALE:
return TextDirectionHeuristicsCompat.LOCALE;
}
Looking at dashboard, I see ~20% of devices using APIs 15 or 16, so I'm thinking we should target API 15 rather than 17.
How should I change this code?
Is there a way to only run this code if the device is new enough? If so, what should the function return for an older device?
Is there an alternative mechanism I should rewrite this method to use?
Never mind. Leaving this question here in case it is useful to others, to know how to work around APIs missing in a given version.
My real issue was not knowing how to mark the calls so that "lint" would not complain about them.
Here is the complete implementation in HorizontalPicker:
private TextDirectionHeuristicCompat getTextDirectionHeuristic() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
return TextDirectionHeuristicsCompat.FIRSTSTRONG_LTR;
} else {
// Always need to resolve layout direction first
final boolean defaultIsRtl = (getLayoutDirection() == LAYOUT_DIRECTION_RTL);
switch (getTextDirection()) {
default:
case TEXT_DIRECTION_FIRST_STRONG:
return (defaultIsRtl ? TextDirectionHeuristicsCompat.FIRSTSTRONG_RTL :
TextDirectionHeuristicsCompat.FIRSTSTRONG_LTR);
case TEXT_DIRECTION_ANY_RTL:
return TextDirectionHeuristicsCompat.ANYRTL_LTR;
case TEXT_DIRECTION_LTR:
return TextDirectionHeuristicsCompat.LTR;
case TEXT_DIRECTION_RTL:
return TextDirectionHeuristicsCompat.RTL;
case TEXT_DIRECTION_LOCALE:
return TextDirectionHeuristicsCompat.LOCALE;
}
}
}
It already has logic to handle older builds!
So all that is needed is to mark the two calls getLayoutDirection() and getTextDirection() so that lint does not complain.
The simplest way to do so, without hiding problems elsewhere, is to mark this method to suppress lint complaints about API versions:
#SuppressLint("NewApi")
private TextDirectionHeuristicCompat getTextDirectionHeuristic() {
...
CAUTION: Only make such a change, after examining the lint complaints and the logic, and your AndroidManifest.xml, to be sure the complaints can be safely ignored.
In my case, manifest has minimum API = 15 and target API = 19, the two complaints were "Call requires API level 17, minimum is 15)", and
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
directs all devices less than 17 to use the one-line implementation, which does not use the API 17 calls. That is, the calls will only be made on devices with API 17 or above.
You can use ViewCompat from android.support.v4 with something like :
if (ViewCompat.getLayoutDirection(mView) == ViewCompat.LAYOUT_DIRECTION_RTL) {
//...
}
This is how I handle a deprecated method:
int layoutDirection ;
if (getContext().getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN_MR1) {
layoutDirection = getLayoutDirection();
}else {
layoutDirection = getResolvedLayoutDirection();
}
The problem is that getResolvedLayoutDirection() has been removed at JELLY_BEAN_MR1 and above. So since my project targets API 20 the method cannot be found and I get an error.
If I keep it foolish:
int layoutDirection = getLayoutDirection();
The project compiles and runs but still I get an error to add either the TargetApi or SuppressLint annotation. getLayoutDirection() docs have:
For compatibility, this will return {#link #LAYOUT_DIRECTION_LTR} if
API version is lower than {#link
android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}.
So suppressing lint should be fine.
Should I suppress the lint error or fix it somehow else (possibly make getResolvedLayoutDirection() accessible)?
The approach to conditionally check whether a method is available is to check the version of Android that the device is running, via Build.VERSION.SDK_INT:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
layoutDirection = getLayoutDirection();
}
else {
layoutDirection = View.LAYOUT_DIRECTION_LTR;
}
And add #TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) to the method containing the above block to indicate to the build tools that, for that individual method, to consider your minSdkVersion to be 17 instead of whatever it normally is, for the purposes of generating Lint warnings and errors.
I want to launch NFC settings activity, which is done using action ACTION_WIRELESS_SETTINGS prior to API level 16. But in API level 16 and above it is done using ACTION_NFC_SETTINGS.
I am compiling my source using Android 4.0.3 which is API level 15.
How can I support for higher level so that it can open NFC settings in all versions.
Do i need to compile my source with API level 16 or higher and make min sdk version 15?
You would typically compile your application with the SDK of the highest API version that you use in your code (or the latest available SDK). In your app's manifest you add the minimum and target SDK versions:
<uses-sdk android:minSdkVersion="..." android:targetSdkVersion="..." />
These values define how your app will be treated on a device in terms of (backwards) compatibility features.
Then, in your code, whenever you use API calles that are not available on a certain API level, you would surround those calles with a check for the Build.VERSION.SDK_INT (as JaKoZo showed).
With regard to the NFC settings, you could do even without that check and instead catch the exception that is thrown when no activity is registered for the ACTION_NFC_SETTINGS intent:
try {
this.startActivityForResult(
new Intent(android.provider.Settings.ACTION_NFC_SETTINGS),
1); // magic number to detect when this startActivityForResult returns
} catch (Exception e) {
try {
this.startActivityForResult(
new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS),
1); // magic number to detect when this startActivityForResult returns
} catch (Exception e1) {
}
}
Instead of the constant ACTION_NFC_SETTINGS, you could also use the hard-coded string "android.settings.NFC_SETTINGS". While I don't really recommend this, you would not need to build against a higher API level (if it's only that constant that causes you to do so).
[...]
this.startActivityForResult(
new Intent("android.settings.NFC_SETTINGS"),
1); // magic number to detect when this startActivityForResult returns
[...]
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
//do stuff
}
u mean this?