Stay awake/wakelock for a specific duration? - java

I need my android application to stay alive for a short specific duration.
I have a long series of updates, during which I keep the screen alive with wake looks. After that is done, there is an dialog informing of the success. Before this one is posted however I've released the wake look. Here I want the application to have a wakelock for 30s and then release it even if the user dos not click ok on the dialog. This is because I dont want to drain the mobile.
Is there an easy way to do this? That is, once I've reached a certain stage in my code I want to have a wakelock for a short duration?

For any long running tasks you should use a service, and for your purpose a ForegroundService.
This comes with the requirement to have a notification visible while your service is running. You can then post a different notification once the process is complete.
This will make your processing resilient to the user stand-by'ing the phone, rotating the phone or going to another app, all of which would interrupt processing if originating in an activity.
http://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification)
For ease of use, I usually override IntentService which has the least amount of boiler code required to get going.

Related

Android: Screen off - notifications delayed / blocking

This issue I have may be only present on devices running Oreo or later as I have only a OnePlus 3T with me for development.
I have a foreground Service that is started using ContextCompat#startForegroundService() and in the service's startCommand method I make sure to create / enable my notification channel so that I can call startForeground with the associated on-going notification.
So I believe, in terms of requirements I get everything right here.
What does my Foreground Service do:
It acts as a Bluetooth Server using the Bluetooth Class RFCOMM BSPP to listen for client to connect ;
When a client connects, it listens for incoming requests ;
It performs the requests and send data accordingly.
My problem lies with the last point. When I connect and ask to send data, two things happen on the phone :
The relevant data is being loaded from the phone and
Once fully loaded, the data is sent to the client.
Each of these operations have their own notifications to display progress to the end-user.
While the first operation is not delayed, the second one may take many minutes (up to 6 in one of my tests).
After further tests, the cause is the notifications because I cancel the first operation notification then I call the second operation, which in turns will display and update its own notification.
So in the end, because I call NotificationManagerCompat.cancel on the first operation notification right before calling the second operation, that call can be delayed for a lot of time. If I don't cancel the notification first, then the second operation is immediately started.
As a solution, I believed that the Doze mode is responsible for that behavior, so I manually white-listed my app the battery optimisation settings of my phone. That did not change a single thing.
Finally, if, at any point, I unlock my phone / turn the screen on, the blocking / delaying notifications get's unlocked immediately and the second process starts right on the bat. So, of course, this behavior does not occur when my phone is plugged into my computer even with screen off.
Is this a bug ? Is this related to doze mode ? I do not know.
[Edit 1]
For better clarity, here is a code snippet that represents the sequence of operations:
loadData() {
... // defer heavy work on a worker thread and updates notification of progress from time to time (every 10%)
notifyDataLoadingStarted(); // on main thread. Displays its notification with progress bar
}
// once the data is fully loaded
onDataLoaded() { // called on the main thread
cancelDataLoadNotification(); // asks the notification manager compat to cancel notification
initiateDataSendingOperation(); // will also defer heavy work on a worker thread and update its notification accordingly
}
What happens is that onDataLoaded is called once the first operation is over. But the problem is that cancelDataLoadNotification is blocking. I am on the main thread and this methods returns very very lately. Hence, this is the reason why initiateDataSendingOperation is greatly delayed.
When I unlock my phone, I could see that the notification of the loading operation is stuck in the middle, as though the loading operation is halted, around 50%. However, this only lasts a fraction of a second because before I know it, the first notification pops out while the the second notification pops in. All in the blink of an eye. Which clearly means that yes, the first operation was indeed over since a long time ago, but its notification was definitely obsolete. And since the second operation would only be initiated when the first notification is cancelled, they you can clearly understand that the second operation is greatly delayed.
That's why my first workaround works if I first start the second operation before canceling the first operation notification.
Nevertheless, in any case, the notifications are still out of date while screen is off.

Android AsyncTask/Service killed before task complete

Synopsis: I need a way to start a task and have it persist through onDestroy() of app until it completes, or ability to pick up where it left off.
In my app, I have a ListView containing some items from a database. Hopefully only about 10-30 items, but potentially thousands (if the user never clears it, although I have prompts to clear it from time to time).
I have set up an AsyncTask to perform clearing the selected items from the list when the user wants to. However, I've noticed that the AsyncTask is killed when onDestroy() is called, for example if the user selects all items to delete, presses delete, then swipes app out of Recents while task is still performing.
I remember learning somewhere that a Service persists longer than an AsyncTask, so when the task gets killed I hand off the data to delete to a Service that I created. It does this by
intent.putIntegerArrayListExtra(list);
and get data from it in the Service. The Service persists far longer than the AsyncTask (only about 4-6 seconds), but still not all the way to completion. I know a little about START_XXXX flags, but that would be bad practice for this task, since they'd either send the whole list back to itself, or never really stop.
What is the preferred method to delete selected items from a database without it stopping when the app is killed, or at least to pick up where it leaves off?
Thanks all!
Your problem is very much like this: You have an application open in your favorite OS which is doing things in the background and then in the middle of it, the user force closes it. Logically, it will stop everything it's doing and stop executing and there's not much you can do to interrupt it.
There's no ideal solution to stop this from happening so what most people end up doing is to warn users that stopping the app when this operation is in process can have unwanted consequences.
In Android however, you have another option which is slightly more robust: you can write a persistent background service what continues running even if your app isn't running, but that still wouldn't solve the problem of what happens if the user switches off the phone when you're deleting from the DB? which would be the next logical question given your context. (personally, I would not recommend this approach for your task).
Best you can do is to maybe write a shared preference for every row you've not yet deleted (this will be the full list of rows you want to delete when you start deleting). For every row (or bunch of rows) you delete, change this preference to remove those rows from the preference and then if the app is interrupted, when you restart your app, read this preference and continue where you left off.
Alternatively, do what others do and warn users (by use of dialogs for instance) that they shouldn't stop the app until the delete is done otherwise bad things happen, etc.
I would strongly discourage you from using a service simply because it lasts longer than an AsyncTask. That's way too hacky and not at all reliable.

Defer timer until SCREEN ON event?

I have a service that runs periodically using a timer to invoke itself, but should not run when the screen is off. When the screen on event is fired, the service should run, but only if it's past when the timer would have fired.
Right now I still run the timer continually, but have the service do nothing if the screen is off. I can also run the service via a broadcast receiver when the screen turns on - but this runs the service every time the screen is turned on, instead of only when it's past when the timer should have run. Recording this state in the service doesn't seem to work as Android will kill the JVM for the app in between executions.
What would be the cleanest/correct way to implement this type of behavior?
So there are a couple of intents that you can listen for, Intent.ACTION_SCREEN_OFF and Intent.ACTION_SCREEN_ON. However, these don't work as manifest receivers, they need to be explicitly registered.
See this answer: https://stackoverflow.com/a/9478013/1306452
In all scenarios, it's going to involve a long running service in order to listen for those events.
One thing to keep in mind is that these intents only listen for when the device becomes non-interactive and vice versa, not specifically when the screen goes off (see the description on the Intents).
The best way for you to achieve this behaviour would be to listen for when these intents with a long lived service, started with START_STICKY to help guarantee that the service is running. The service can register a receiver for the SCREEN_ON and OFF events, and when it gets these events either do nothing if the timer has not elapsed, or continue if it has.
This won't be nice on your battery life, and what ever you are doing it doesn't sound like it's going to be a pleasent user experience. You might also want to step back and see if there's another way around this obstacle (my 2 cents).

Exiting app after completion of all crouton toasts

I am using Crouton as alternative to native android toasts. I have to display 5-6 croutons one after the another and then call System.exit(0) to exit my app.
The problem is, I see first crouton for 1-2 seconds and the app just exits! The rest croutons aren't displayed at all. This is because when the code is being executed the undisplayed croutons are added to queue. And when it comes to System.exit(0) it exits the app without displaying those queued croutons. I have tried searching for solution for this and came across a solution in which I have to create a new thread, then sleep it for time = sum of durations of necessary croutons and then call System.exit in that thread. But then if I have more or less croutons in another situation then that becomes useless.
So can anyone think of a solution?
Why do you have to quit the app?
In general, in Android, applications should not quit, and show not provide a way for the user to quit them. Quitting an app is handled by the system when the user navigates away from it and goes back to the home screen.
If your application must quit (for example, because of an unexpected condition it can't deal with) and you want to make sure the user sees the information, then the best approach would be to use an AlertDialog to display the information.
So, long story short: revise your UI... if you're sure that this is the right way to do it, then simply don't call System.exit(0). Just show the toasts and then stick around. Eventually the system will decide to quit your app when memory is needed.

Handler.postDelayed not called when mobilephone in standby mode

I'm trying to write a simple app that should mute my mobile phone for a given time. It's my first Android app, but after many hours of reading I think it is nearly completed. But it still has one problem that I can not fix.
I'm using a activity to display the GUI. It has Buttons to set the start and end time, and everything else needed. When the user has entered all the parameters, they are passed to a service. This service uses a handler object, to register 2 callbacks (with Handler.postDelayed). One for start Mute and one for End Mute (in SetMuteIntervall).
The first tests seemed to work, but if I try to mute it for like 30 minutes, it never unmutes. I think it has something to do with the fact, that the mobilephone is or was in standby mode. I also tried to use Handler.postAt() but that didn't work either (and time relative to uptime was somewhat confusing).
So, what should I do to guarantee, that my callbacks are called, regardless whether the phone is in standby or not?
Here's the source of my program:
http://pastebin.com/XAgCeAq9
http://pastebin.com/33nepFV5
Try to use AlarmManager for planning some actions in future. AlarmManager is not standby-mode-dependend and will fire even if device is sleeping.
Your thread are actually stopped then the phone is in stand by mode. If you still want to use thread you can use WakeLock to prevent CPU from going to stand by mode (but still to switch screen off) but this is not the best way in your case.

Categories

Resources