Unexpected backwards compatibility or Why Isn't My App Crashing? - android

I'm developing an application with a minSdkVersion of 9, a targetSdkVersion of 17. I am performing some Bitmap pixel manipulation, so at one point I call the function Bitmpap.setHasAlpha() to enable the alpha channel for the Bitmap so I can set certain (and only certain!) pixels to be transparent.
The problem is that Bitmap.setHasAlpha() was only added in API 12--and this is where the mystery comes in. Lint is not complaining about my usage of this call (well... as a general rule. Every once in a while Eclipse will complain about it, and then when I restart it everything goes back to normal), when I run my app on a couple of different Gingerbread (2.3.3 and 2.3.5) devices everything runs properly.
So... as strange as this question sounds, why isn't my app crashing?

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3.5_r1/android/graphics/Bitmap.java?av=f As you see mate the function existed before but not documented

minSdkVersion is a check designed to prevent download and installation of the app on older devices that do NOT have even framework corresponding to the minSdk.
targetSdkVersion is used to determine if any compatibility "workarounds" need to be enabled to ensure the behavior is as close to what is seen in targetSdk
By setting minSdkVersion=9 you signal that the gingerbread devices be allowed to download and install your app. By setting
targetSdkVersion=17 you signal that any workarounds be invoked to allow the device to retain as much functionality as possible from the later sdk.
Also as mentioned in Pulkits' answer the setHasAlpha() API seems to be present even in the 2.3.4 Android framework, albeit not officially documented at that time.

Related

How to remove API level styles higher than my API level used?

All these resources, how can I stop Android Studio from adding them to the build? And where do they even come from?
I've recently downgraded my project because I intend to make an app for Honeycomb (I expect my audience to use relatively old phones). But after I did that, I got all these errors and I've no idea how to stop Gradle from adding them to the build.
how can I stop Android Studio from adding them to the build?
Technically speaking, you get rid of the code that is trying to add them.
Practically speaking, they are most likely serving a purpose for you, and that your problem is that you changed the compileSdkVersion to too low of a value.
And where do they even come from?
Libraries, most likely.
I've recently downgraded my project because I intend to make an app for Honeycomb
My guess is that you changed your compileSdkVersion. Change it back. Your minSdkVersion needs to be low enough to support your older devices; your compileSdkVersion needs to be high enough to support all of your code. Typically, compileSdkVersion is set to a recent version (e.g., 25 at the moment).
I intend to make an app for Honeycomb (I expect my audience to use relatively old phones)
Honeycomb (Android 3.x) was never used on phones.

Determine if screen is on or off on Android versions 15 - present

I am writing an SDK that will be used by Android devices with API level 15 and up. I'm currently targeting sdk version 22. What I'm trying to accomplish is to determine whether or not the screen is on or off. Sometimes I will be doing this while the app is in the foreground or background and sometimes I will be doing this when the app is closed, by using an Alarm. What I want to be able to do is ask the framework if the screen is on or off, but it doesn't look like that's possible for android versions <= 19.
It looks like sdk version 19 allows a device to use PowerManager.isScreenOn() to determine the state of the screen, but when version 20 came out that method was deprecated and now you can call PowerManager.isInteractive() but that only works on devices running API 20 and up. If you try to call isScreenOn() using a device running API 19 or less the call really just wraps isInteractive() and you end up getting a method not found in your logs and don't actually get the data you desire.
So it seems like if I always want to know the current state of the screen for devices <= 19 that one work around is to start a background service that is basically always runs and that registers a broadcast receiver that looks for the ACTION_SCREEN_ON and ACTION_SCREEN_OFF Intents. That obviously isn't desirable because then I have to have an always on service which is not recommended.
I suppose another workaround is to compile agains sdk 19 when I build, which would make the isScreenOn() call available (and make the isInteractive() call unavailable). That might be a possibility but seems like a poor workaround because I'd essentially be stuck at this sdk level until either the framework backports this functionality or sdks 15 - 19 are used by few enough users that it no longer makes sense to support them.
Am I correct in my assessment of the situation?
Can anyone comment on the two work arounds proposed or suggest alternatives?

In Android, is there a way to set "android:configChanges" for an activity at runtime instead of in the manifest?

My app is set to run on minSdk = 5, but the vast majority of users are using SDK 8 (FroYo) and higher. I want to be able to use the android:configChanges="uiMode" for my main activity, but I can't do it because that mode wasn't introduced until SDK level 8. So, I was hoping that I could do it at runtime -- check which SDK level is running on the device, and then use reflection to add that parameter.
Is that possible?
EDIT:
The problem is that whenever a user's phone is connected to the dock, my app gets terminated, and then re-created. I'm trying to avoid that by including the android:configChanges="uiMode".
After much poring through the Android Reference, there is very little you can change from the manifest at runtime. This is due to security because through the PackageManager, one can gain very specific information about any application on the device. While it is easy to enable/disable a given Component, in most other circumstances, you can only read manifest information... not write it.
Alternatives
You could potentially make a separate APK with API Level 8 support.
You could manually check for configuration state and run your code when it changes. The object reference for configuration is here.
Edit: (new info)
While you cannot change the configChanges, I found this question that is closely related to yours. It turns out that you might not have to. It implies that you can use Android's backward compatibility mode when supporting new configChanges. In case the link above is broken, here is the URL: https://stackoverflow.com/a/7893148/501932
To put this to use for you, it suggests setting a new targetSdk while maintaining your original minimumSdk. It also requires that you have the updated SDK, itself. Apparently, this was a huge deal for users that utilized that AdMob API.
App Configuration for forward compatibility
The answer I provided is a simple what to do, but not much or the why, this should update the answer as well as act as apology to the SO community for sparring with the poster, which was pointless and added nothing to the conversation.
I think it’s an important point to expand upon this issue since these kind of questions come up a lot and developers in a hurry (aren’t we all) and we have a tendency to cut/copy/paste and worry about the why of it later which mostly works out but occasionally just adds to the problems.
If you understand how the android runtime actually works you can often solve these types of problems by applying a simple pattern of best practices by using the block in your manifest, and making good use of the Build Target when compiling your app, followed by some simple testing at the compile and run time levels.
Manifest
minSdkVersion =
Pretty straight forward it’s the lowest build target you will support on a specific device. If you don’t set this it defaults to 1.
The only caveat here is that if your Build Target is higher than your minSdkVersion than you can potentially call API’s that don’t exist on the device, more on that under Build Target.
This will filter you app from on the various market/play repositories for devices that have lower OS support.
How you make this determination is up to you, if you must have your app run on every device ok, but take a look at Platform Distribution to make an informed decision.
If you are willing to bypass 0.9% of the market then target 2.1 which seems reasonable but that’s a decision for a developer/company to make, if you can bypass 25% of the market then go with 2.3 which has significant advantages but is a bit hard to swallow for most general purpose app’s.
The linked chart is updated from time to time.
targetSdk =
If you don’t apply this value then it defaults to whatever minSdkVersion you set. This means that when you run on a device with higher OS support certain new looks and or behaviors that are implemented will be bypassed in favor of the older way of doing things.
For instance if you apply 10 to the minSdkVersion and then your app runs on a device with gingerbread (11) it will not attempt to use the holo theme, or disable screen compatibility mode. In general this might give your app a “Dated” look and feel.
If on the other hand you set this to something higher, like 11, then the system will use the native look and feel of the OS up to that value you set. Best practices is to set this as high as possible and then to test on the higher level device in the emulator to make sure this is acceptable.
Some of the changes that effect compatibility behavior between OS jumps are documented here Differences between OS's
This will not stop you from running on earlier devices, or effect those earlier devices look or feel (see ActionBarSherlock and the Android Support Library if that’s your goal)
maxSdkVersion =
In general this does just what it says it does, it restricts availability and deployment of your application on devices that have a higher OS level from Google market/play.
On android 2.0- it will also refuse to install the apk, and will even remove your app if a device is updated to a level higher than this setting, 2.0.1+ removed the second part of this behavior but the markets will still filter based on it.
In general there is no reason to usually set this value, so leave it blank.
Build Target
When you set a build target in eclipse (or otherwise) you are telling the complier which API’s, constants, etc. should be VISIBLE to your application.
In general it adds a jar file that has all of these definitions/declarations but of course not the actual classes/methods so that you can compile your application for any target OS you desire.
When your app runs on a device it links to the actual android OS/support jar file(s) (or blows chunks if they are not there)
If you select a build target higher than you are willing to support then bad things can of course happen when you try and call method that does not exist, or even a class that does not exist on the Older OS.
If on the other hand you are willing to carefully manage and test this then you can obtain forward compatibility in the sense that you can use the new API’s on newer devices so long as you don’t attempt to do so on earlier devices.
Best Practices – Short Version
This is what the poster is trying to accomplish and if best practices are followed it works out well, these are in general
minSdkVersion = lowest general API you will support
targetSdkVersion = highest behavioral model you are willing to allow
maxSdkVersion = leave it blank
Build Target = generally as high as is currently supported
The real caveat is that you have to avoid API mismatches between older and newer versions, and make sure your app looks and acts ok on the higher version.
In general methods/classes that are higher than your minimum targeted OS should be used sparingly and tested at both the compile and runtime level since it requires some effort to use them safely.
Here is how I go about it
minSdkVersion = 7 ( I can live with a 0.9% clip again your choice )
targetSdkVersion =15 ( highest as of this writing )
maxSdkVersion = ( blank )
Build Target = 15
When developing I never use an API not available on 7 unless I have a real need to do that, in the posters question he could have used a broadcast received to get similar functionality back to 6/7 (2.0/2.1) but he states he needs API 3 support so he has to support forward compatibility.
One tool you can use, and most don’t just to keep things straight is to set the API level on the developer.android.com website to your minimum SDK level, this gives you a heads up when developing that you will have to support forward compatibility.
It will still show the other API calls but it will gray them out telling you that extra effort will be needed to support them
If you do need to use a newer API you will need to do an if then else so that they are only called on the newer device, this will allow you to support the new functionality without getting a force close on older devices.
So in general if you support higher API levels those calls should be wrapped with something like this (note the .SDK_INT is a since API 4 test)
If ( Build.VERSION.SDK_INT >= API11_SUPPORT ) {
switch(newConfig.uiMode) {
case ...
}
Testing – manual method (CI integration methods are left up to the reader ;-)
Compile with the build target set to the minSdkVersion – this will give you compile errors on any newer API’s that you are using, check them out and if you handled them great, if not now is the time.
For every issue I see at step 1 I add two items to the code (manifests/xml )
// TODO Compatibility xxx
if (DEBUG) Log.i(“MyApp”,” Compatibility xxx”);
I can then use the eclipse TODO pane to check off compatibility issues before ship and test them against the lowest/highest and any significant in between OS versions
Test on minSDKVersion device/emulator, this is a bit tricky if you are not doing comprehensive testing, in general use step 1 above to make sure I exercise those blocks of code
Test on Build Target device/emulator to make sure look and feel work as expected
If you think it’s a bit of work it is, but when you need it you should do it right and make sure your app does not break.
Hopefully this is useful to someone trying to figure out similar situations, below was my second response to the poster, Cheers.
UPDATE:
I still have no idea what the author is asking, but if he is asking if there is a way to detect the configuration changes in regard to uiMode (docking stuff) on 7 and below using the onConfigurationChanged handler then no since that was only introduced in API 8.
There is a broadcast event sent in API 2.0+ systems, but apparently that has some issues and does not seem to be completely reliable
If he is asking if there is a way to support it on devices that are API 8 and above via the onConfigurationChanged handler by setting the flag in manifest for the activity then of course there is
Of course he may be asking about something totally different, it's hard to tell exactly what he is looking to do given his post none the less in the spirit of cooperation:
Select an API from project properties that is >= 8, best practices is to use the highest API available when you create your app for just this reason BUT care must be taken not to call any API's that are not available on the device.
Then in the manifest use (duh)
<activity
android:name=".myActivity"
android:configChanges="uiMode|orientation|keyboardHidden"
This compiles fine (and that is really the only issue and why you need to set a higher api in the eclipse project properties) this will run fine on 7 and below it just wont trigger any events because of course API 7 and below devices won't recognize the uiMode flag (duh)
API 8 and above of course will recognize it and send the proper event so on api 7 the log will be written, on api 8+ it will (if docked etc) of course the calls that are made if it does happen will most likely be 8+ related so you would need a OS check block before calling them.
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.i("myActivity","uiMode="+newConfig.uiMode);
}
If you compile and run on a 7 API emulator and fire a dock broadcast nothing happens, change to a 8 API emulator and it does
adb shell am broadcast -a android.intent.action.DOCK_EVENT --ei android.intent.extra.DOCK_STATE 2

Ensure Android project doesn't call APIs with newer-than-intended API level

When developing an Android app, let's say I want it to be compatible with 1.6 (API Level 4) devices, but still enabling 2.2 (API Level 8) features such as adding android:installLocation to enable moving app to SD card. Therefore I set Eclipse to compile against 2.2 SDK instead of 1.6 SDK.
Adding unknown attribute like android:installLocation doesn't crash the app when running in 1.6 device, but in case when coding I call some API that is unavailable in 1.6, such as android.util.Pair or Base64, the app will crash when running in 1.6.
Is it possible (e.g. via an Eclipse plugin) in build-time (not in run-time!) to check whether the project is still compatible with 1.6, in other words, check whether there is any API calls to any of the methods/classes requiring more than 1.6 (API Level 4)?
The best way to check if your app uses a non-existing API on older handsets is to change the target to the old version (starting from the minimal one you support) and seeing if you have any compilation errors... This will point you to non-compatible API calls.
At least that's the way I do it.
This is a tough problem to handle gracefully in code. I asked a very similar question here.
It seems to me that you may be asking the wrong question. Checking for calls to new API features is reasonable, but if you want to make your app work well over multiple versions, you will have to have code that makes calls to old and new API levels as appropriate. There are many ways to do this and it's considered a best practice.
In that case, you may want to downgrade your target version and check that all the errors that come up in Eclipse are handled well in your code (and of course try it in the right emulator versions).
I know this question is ancient, but there is a "holy grail" solution to this issue (at least from your users' point of view):
You can publish two versions of your app, one requiring API level 8 and another requiring API level 4. Then, use versionCode 100, 101, 102, 103, ... for your level 4 version and versionCode 200, 201, 202, 203, ... for your level 8 version.
That way, if a user has API level 8 available, they get offered only the level 8 version of your app as it has the higher versionCode. And users that only have API level 4 through 7 available, get offered only the other version as the other one is incompatible.
It's a little bit more of a pain to maintain, but it has the (potentially huge) advantage that you can customize the reduced-features version to still provide a complete experience (no grayed-out buttons, etc.), and you can even keep the APK size smaller for that version as you don't even need to ship the code or related resources for the unavailable features.
You can find more details in Android's Multiple APK Support documentation.

Is there a compendium of behavioral changes based on increasing Android targets?

In Android 2.0, changes were made so that services that were killed would be restarted with a null Intent by default. However, this only applied if the app targeted API Level 5 or greater (I'm simplifying a little, see http://android-developers.blogspot.com/2010/02/service-api-changes-starting-with.html). Since my app targeted API level 4, I was hiding APIs greater than level 5, and was not aware of this.
When I needed a feature from Froyo, I bumped the targeted version, and suddenly my app was crashing because my onStart method was not prepared for a null Intent.
It was an easy fix, but I'm concerned that there are other behavioral changes like this that I'm not aware of when changing the targeted version. This case was not immediately obvious, either, because our service normally stops itself, so it requires circumstances that result in the service being stopped in an unusual way.
Has Google or anyone put together a list describing things like this to look out for when increasing the target version?
There is API differences report: http://developer.android.com/sdk/api_diff/10/changes.html
The change you mention is also listed: API 4->5 Service.onStart(..)
I just discovered another resource, so I'm leaving it as an answer here as well. It's not as thorough as the API diff, but it is helpful. The Build.VERSION_CODES documentation has a summary of major behavioral differences:
http://developer.android.com/reference/android/os/Build.VERSION_CODES.html

Categories

Resources