I'm building a call blocking app that uses Itelephony to block calls. I want my app to work on API levels starting at API 16. In order for my App to work on current API levels, I need to use CallScreeningService to screen phone calls. The issue is that CallScreeningService only works on API levels 24 and up. How can I make it so Itelephony blocks call for API level below 24 and this class blocks calls for API levels 24 and up?
import android.telecom.Call;
import android.telecom.CallScreeningService;
import android.util.Log;
public class CallScreenService extends CallScreeningService {
private static final int REQUEST_ID = 1;
#Override
public void onScreenCall(Call.Details callDetails) {
CallResponse.Builder response = new CallResponse.Builder();
Log.e("CallBouncer", "Call screening service triggered");
}
}
Hit Alt + Enter (on a Mac) on the error to get a quick fix to your issue like this:
Here you see that you can fix the issue by using one of two annotations.
The #RequiresApi marks the class as having to be run on a specific API level or above, despite your min sdk level.
#RequiresApi(Build.VERSION_CODES.N)
public class CallScreenService extends CallScreeningService {
private static final int REQUEST_ID = 1;
#Override
public void onScreenCall(Call.Details callDetails) {
CallResponse.Builder response = new CallResponse.Builder();
Log.e("CallBouncer", "Call screening service triggered");
}
}
This will cause a build error if you try to use it outside of a version check.
Then you can do conditional version checking to use your new class or the old one.
Hope that helps!
if(android.os.Build.VERSION.SDK_INT >= 24){
//do the thing that requires SDK 24 and greater
else{
//do the thing that requires less than SDK 24
}
SDK_INT documentation
SDK_INT is the SDK version of the software currently running on this hardware device. This value never changes while a device is booted, but it may increase when the hardware manufacturer provides an OTA update.
Here is a link to all the SDK codes:
SDK Version Codes
Related
Utilizing onSignalStrengthsChanged, getAllCellInfo(), and related methods, my app monitors cell signal data and displays the results in realtime. My code works very well when targeting API 28 and lower, automatically refreshing the data as it changes. Targeting API 29 results in some Android 10 devices failing to update the data -- but not all.
I discovered TelephonyManager.requestCellInfoUpdate() was added to API 29, which may(?) be needed to resolve this issue. However, I have been unable to find any information about this method beyond the concise definition on the Android Reference. Does this method need to be used to refresh cell info? Are any code samples or further explanations available?
If that method is not relevant, is there another change in API 29 that could cause this behavior? ACCESS_FINE_LOCATION is confirmed to be granted, which appears to be the only other relevant API change.
I have noticed the same behaviour targeting Android 10 (API Level 29). The only workaround I have found is to regularly poll the API and look for changes.
Example code below:
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
tm.requestCellInfoUpdate(minThreadExecutor, new TelephonyManager.CellInfoCallback() {
#Override
public void onCellInfo(#NonNull List<CellInfo> list) {
//Extract needed data
}
});
}
}, 1000, 1000 );
Reading the docs there is a mention of this in the getAllCellInfo() documentation.
Apps targeting Android Q or higher will no longer trigger a refresh of the cached CellInfo by invoking this API. Instead, those apps will receive the latest cached results, which may not be current. Apps targeting Android Q or higher that wish to request updated CellInfo should call requestCellInfoUpdate(); however, in all cases, updates will be rate-limited and are not guaranteed. To determine the recency of CellInfo data, callers should check CellInfo#getTimeStamp().
So the preference is if you are targeting Android Q or higher, you should be opting for requestCellInfoUpdate()
// 1. Create a TelephonyManager instance
telephonyManager = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
// 2. Define a CellInfoCallback callback
TelephonyManager.CellInfoCallback cellInfoCallback = new TelephonyManager.CellInfoCallback() {
#Override
public void onCellInfo(List<CellInfo> cellInfo) {
// DO SOMETHING
}
}
// 3. Now you can call the method to DO SOMETHING
telephonyManager.requestCellInfoUpdate(this.getMainExecutor(), cellInfoCallback);
I'm using a method with boolean return type for api 19 while my app supports min sdk 15, what will the method return incase the api is less than 19 ?
#TargetApi(19)
public static boolean isFeatureXEnabled(Context context) {
some logic
return true/false;
}
what do I get in return for API <19 when calling?
classInstance.isFeatureXEnabled(context);
let's understand #TargetApi(19)
You are using a feature which is not available on minimum SDK so
Compiler : you cannot use this feature , it is not supported by min sdk
You: i know what i am doing so hush , take this #TargetApi(19)
Compiler : so now it is your responsibility to check the API level and call this function accordingly
what will the method return incase the api is less than 19
If the code inside this function is not supported by minsdk then most likely a crash otherwise your result of your logical calculation
you can do something like this
#TargetApi(19)
public static boolean isFeatureXEnabled(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
some logic
return true/false;
}
return false;
}
#TargetApi
Indicates that Lint should treat this type as targeting a given API level, no matter what the project target is — https://developer.android.com/reference/android/annotation/TargetApi.html
It means it is just used by Lint to hide/suppress the warning. It has ho effect in the return value.
I've a problem with checking is device supports Mutli Window Mode. I'm using this function to check it isInMultiWindowMode() but it've added in API 24, and when i'm runs my app on device with lower api version it cause an exception. There is any replacement for this function for lower api versions?
There is any replacement for this function for lower api versions?
Not in the Android SDK. There is no multi-window mode (from the Android SDK's standpoint) prior to API Level 23. And, for whatever reason, Google elected not to add isInMultiWindowMode() to ActivityCompat, perhaps because they cannot support the corresponding event (onMultiWindowModeChanged()).
So, here's a free replacement method:
public static boolean isInMultiWindowMode(Activity a) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
return false;
}
return a.isInMultiWindowMode();
}
Add that to some utility class somewhere and call it as needed.
Also note that isInMultiWindowMode() suffers from a race condition that makes it unreliable, IMHO.
What #CommonsWare explained is true, it is a race condition. Hence, isInMultiWindowMode() will give actual result if you call it from inside post method:
View yourView = findViewById(R.id.yourViewId);
yourView.post(new Runnable() {
#Override
public void run() {
boolean actualResult = isInMultiWindowMode();
}
});
In some case, I found the android studio lint does not show the message “Call requires API level xxx (current min is xxx)”.
public class TestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_enter_leave_wifi);
if(isDestroyed()){
}
}
private class Test {
Test(){
if (isDestroyed()){
}
}
}
I found there is the error message in the isDestroyed() in the onCreate, but there is no such error tips in the constructor of Test
How to solve this issue?
UPDATE:
Current minSdkVersion is 14. That's why the isDestroyed(), which requires 17, in onCreate gives the error tip
The functionality you want to perform requires higher API level access than your current minimum in which that functionality/access is not available.
In order to achieve that, simply change the API level of current minimum to the required one in app:gradle file. And then recompile the project.
Good Luck
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)
}
}