Android check is bluetooth in doze mode - android

Good day.
I would like to know if the bluetooth scanning is unavailable now (locked by doze mode?).
Now i check it by this method:
fun isInDozeMode(context: Context) : Boolean {
val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && powerManager.isDeviceIdleMode
}
But this method returns true even if i receive bluetooth (iBeacon) event just now.

Bluetooth is not directly affected by Doze mode:
Doze does not affect the ability to do bluetooth scans or run Handler-based timers, but it does affect the ability to use the Android AlarmManager system, which some beacon-based systems use to schedule bluetooth scans. For apps based on the Android Beacon Library, the disabling of Alarms does not cause problems in scanning for beacons because it only uses Alarms as a backup should Handler-based timers fail. Tests on a Nexus 9 running the third preview release of Android M (build number MPA44l) show that beacon detection continues normally under Doze.
See my blog post here. While that blog post was written for Android 6.0, subsequent doze changes added in 7.0 also do not affect Bluetooth scanning. See here.

Detect when the app enters/exits idle mode due to Doze
The OS will send a DEVICE_IDLE_MODE_CHANGED broadcast so we can track when the app has entered or exited idle mode.
Note: This broadcast will be sent when the device occasionally starts or ends the 10 minute idle maintenance window.
See: https://developer.android.com/reference/android/os/PowerManager.html#ACTION_DEVICE_IDLE_MODE_CHANGED)

Related

How to solve SCAN_FAILED_APPLICATION_REGISTRATION_FAILED

I am trying to perform BLE scans in a foreground service (Android 12) after some start scan end stop scan I receive the error SCAN_FAILED_APPLICATION_REGISTRATION_FAILED, I cannot figure out what is the reason of the error.
I do startScan and stopScan in sequence (the scan is a long-running scan)
The app target SDK 32 so I have the new Bluetooth permissions.
This is the complete scenario:
I open the app and I start the foreground service
I close the application (the foreground service is still running)
The foreground service scan and connect to my device and then I stop scanning
I turn off my BLE device and the foreground service start to scan again
I turn on my ble device and the foreground service detect it and connect to it.
Repeat step 4 and suddenly the error SCAN_FAILED_APPLICATION_REGISTRATION_FAILED show.
I also notice this error in the logcat App 'com.sample.xxx' is scanning too much clientif (I look into AOSP source code and seems that this string is specific of Xiaomi ROM)
https://github.com/appersiano/TestingBackgroundConnection
P.S. Tested on Xiaomi Mi11 Lite 5g
How can I solve?
you should not scan more than 5 times in 30s.
GattService:
This constant defines the time window an app can scan multiple times.
Any single app can scan up to |NUM_SCAN_DURATIONS_KEPT| times during
this window.
Once they reach this limit, they must wait until their earliest recorded scan exits this window.
static final int NUM_SCAN_DURATIONS_KEPT = 5;
static final long EXCESSIVE_SCANNING_PERIOD_MS = 30 * 1000;

Restrictions when scanning in background on Android 10?

There seems to be a lot of "hidden features" regarding Bluetooth scanning on Android.
For starters there is a "30s limit" (Android 7.0 ble scan no result). Then you have to set a ScanFilter in background mode otherwise you get no results (can't find a reference for this one).
Most recently I discovered that I don't get any scan results when I enable scanning using the following scan mode with the screen turned off (after 30s or so) on Android 10 (I have observed this behavior on Google Pixel 3 and Google Pixel 4, it works fine on older Androids):
/**
* Perform Bluetooth LE scan in balanced power mode. Scan results are returned at a rate that
* provides a good trade-off between scan frequency and power consumption.
*/
public static final int SCAN_MODE_BALANCED = 1;
There is another scan mode (which I have not tried yet):
/**
* Perform Bluetooth LE scan in low power mode. This is the default scan mode as it consumes the
* least power. This mode is enforced if the scanning application is not in foreground.
*/
public static final int SCAN_MODE_LOW_POWER = 0;
Question: Should I interpret this comment "is enforced" as enabling scanning with something other than SCAN_MODE_LOW_POWER will give me no scan results? Can somebody confirm this?
I will investigate further on my own, but it takes time...
Note: I have a foreground service and I can see in the ADB logs that the scanner is enabled / disabled periodically. But I don't get any scan results...
Update: I've now made sure to use SCAN_MODE_LOW_POWER when in background mode but still I get no results. I have no idea what's going on.
Update 2: I tried running an older version of the app (not compiled for Android 10) and that worked fine
Update 3: I disabled battery optimizations for the app just in case. This did not help:
Go to Settings > Apps > Your app > Advanced > Battery > Battery optimization
Change view to All apps
Search for your app
Choose Not optimized
Android 10 requires new permissions in order to get BLE scans to return results. Unfortunately, the scan will simply not return results instead of logging a warning. The new permissions are ACCESS_FINE_LOCATION instead of ACCESS_COARSE_LOCATION required for sdk versions 23 through 28 and if you need to perform BLE scans while the app is in the background (even if you have a foreground service) you will need ACCESS_BACKGROUND_LOCATION. You must list these permissions in the manifest and prompt the user to grant them at runtime. There's a similar question here with a little more info in the answers: Android 10 not working with BLE Bluetooth scanning

Android Beacon Library - extending BluetoothMedic for unconditional resets?

I have an Asus P00A tablet (Android 7.0, API24) on which the BLE stops after some hours. (This affects any BLE app, not just my app using Android Beacon Library). Apps start working again if I manually switch off BLE then switch it back on.
The BluetoothMedic auto-fix system did not work for my tablet. It runs every 15 minutes but does not find a fault and so does not "power cycle" the Bluetooth. However, I hacked the BluetoothMedic class, adding this:
public void cycleBluetooth(Context context) {...}
and attached this to a button. I find this will restore BLE functionality. So I wondered what would happen if I unconditionally reset the BLE every 15 minutes. I added:
public static final int ALWAYS_RESET = 4;
and then call medic.enablePeriodicTests(context, BluetoothMedic.ALWAYS_RESET);
and add code inside BluetoothTestJob.onStartJob() which then calls BluetoothMedic.cycleBluetooth(). This behaves as expected and so far my app has run perfectly for 18 hours.
I am interested in any advice, such as:
1 Are there any tests other than the two in BluetoothMedic that I can run to detect that my tablet's Bluetooth has stopped? (I am happy to experiment).
2 Any comments on the hack I describe above? Should it be OK to unconditionally reset the Bluetooth every 15 minutes?
3 If the Bluetooth is reset ("power cycled") then is the rest of the Android Bluetooth Library OK with this? That is, will it carry on with monitoring and ranging that has been previously set up, or does the application code need to set take any action to get things going again? Note that this would apply to resets by the existing enablePowerCycleOnFailures() code as well as my ALWAYS_RESET hack above. (Maybe there are some crashes that could happen if the power cycling came at the wrong time?).
4 Could I suggest adding a callback so the application can learn if the Bluetooth has been cycled? Perhaps as a parameter to enablePowerCycleOnFailures()
5 I understand that background activities can be stopped by the OS, especially with Android 8. Would this also affect the regular 15 minute tests set up by enablePeriodicTests()?
The Android Beacon LIbrary's BluetoothMedic, as currently built, relies on the operating system's error code returned by a scan failure (or an advertising failure) to decide if the bluetooth stack is in a bad state warranting a power cycle.
For scans, if the onScanFailed callback is called with an error code of SCAN_FAILED_APPLICATION_REGISTRATION_FAILED which has the value of 2, the module considers it worthy of a power cycle..
For advertisements, if the onStartFailed callback is called with an error code of ADVERTISE_FAILED_INTERNAL_ERROR which has a value of 4, the module considers it worth of a power cycle..
These values were determined via experimentation, witnessing that on some devices, once an error callback is called with these values, bluetooth on the device would not work again without turning it off and back on. You can see the discussion of this in this thread.
You may want to see if there are other error codes on the Asus P00A that indicate a problem worthy of cycling bluetooth. To do this, wait for a failure, and see if attempts to start scanning call the onScanFailed callback with a distinct error code. If such error codes exist, this would be a better solution than cycling power to bluetooth regularly, as cycling power to bluetooth does break BLE GATT connections and the operation of bluetooth classic functions like speakers. The Android Beacon Library itself recovers from these power cycles just fine, although it will obviously not detect beacons until bluetooth is back on.
Because the BluetoothMedic uses the Android Job Scheduler for periodic tests, it is not affected by background limitations on Android 8+.
If you are interested in augmenting these functions in the library, please feel free to open an issue in the Github repo, and issue a Pull Request if you have code to share.

Android Application Bluetooth visibility duration

Is there a way to let my application be discoverable for a time the app is running? I tried to do this with
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0);
startActivityForResult(discoverableIntent, DISC_DURATION);
as shown on Android Developers, but the Duration of 0 doesn't work so the default value 120 is set. Is there a way to set it as visible all the time?
there is no mean for keep Bluetooth discoverable all time.
At the time when you want to find some new devices or other devices can find your device you have to make it discoverable.
After that your device will interchange a shared MAC id and will make a paired.
Performing device discovery is a heavy procedure for the Bluetooth adapter and will consume a lot of its resources. Once you have found a device to connect, be certain that you always stop discovery with cancelDiscovery() before attempting a connection. Also, if you already hold a connection with a device, then performing discovery can significantly reduce the bandwidth available for the connection, so you should not perform discovery while connected.
for more info see this
http://developer.android.com/guide/topics/wireless/bluetooth.html#DiscoveringDevices
There is no way for you to set bluetooth to be continuously discoverable on any 2.* version of Android; see this bug report. It seems like the limitation has been removed in 3.* versions, but I haven't seen any confirmation of this.
I come to the conclusion on three devices I have.
ANDROID v 4.3 and higher : EXTRA_DISCOVERABLE_DURATION 0 works no limit
ANDROIND v 4.1 : EXTRA_DISCOVERABLE_DURATION 0 is max 1 hour. Have to change manually to no limit in parameters.

Make Bluetooth on Android 2.1 discoverable indefinitely

I'm working on a research project which involves Bluetooth and the Android OS. I need to make Bluetooth discoverable indefinitely in order for the project to continue.
The Problem:
Android limits discoverability to 300 seconds.
I cannot ask the user every 300 seconds to turn discoverability back on as my application is designed to run in the background without disturbing the user.
As far as I am aware, there is no way to increase the time though Android's GUI. Some sources have called this a safety feature, others have called this a bug. There may be a bit of truth in both...
What I'm Trying / Have Tried:
I'm trying to edit a stable release of cyanogenmod to turn the discoverability timer off (it's possible; there's a configuration file that needs to have a single number changed). This isn't working because I'm having verification problems with the resulting package.
During the past week, I downloaded the cyanogenmod source code, changed a relevant class in the hope that it would make Bluetooth discoverable indefinitely, and tried to recompile. This did not work because (a) the repo is frequently changed, leading to an unstable code base which fails to compile (OR, it could be that I'm using it incorrectly; just because it looked like it was the code's fault in many instances doesn't mean I should blame it for all the problems I encountered!) and (b) the repo decides to periodically "ignore" me (but not always, as I have gotten the code base before!), replying to my synchronization/connection attempts with:
fatal: The remote end hung up unexpectedly
As you might imagine, the above two issues are problematic and very frustrating to deal with.
More Info:
I'm running Android 2.1 via cyanogenmod (v5 I believe). This means the phone is also rooted.
I have a developer phone, which means that the bootloader is unlocked.
My phone is an HTC Magic (32B).
The Big Question:
How can I make Bluetooth indefinitely discoverable on Android?
See the following link:
http://developer.android.com/guide/topics/wireless/bluetooth.html#ConnectingDevices
Specifically, the last sentence in the paragraph below:
Enabling discoverability
If you would like to make the local device discoverable to other devices, call startActivityForResult(Intent, int) with the ACTION_REQUEST_DISCOVERABLE action Intent. This will issue a request to enable discoverable mode through the system settings (without stopping your application). By default, the device will become discoverable for 120 seconds. You can define a different duration by adding the EXTRA_DISCOVERABLE_DURATION Intent extra. The maximum duration an app can set is 3600 seconds, and a value of 0 means the device is always discoverable.
So, this should work:
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0);
startActivity(discoverableIntent);
If you check out the BluetoothAdapter class
you will find the hidden method:
public void setDiscoverableTimeout(int timeout)
Now you only have to find out how to use it. You have to do a method invocation to do so.

Categories

Resources