Timer stops every time the phone sleeps - android

I'm creating this incredibly simple app, since I'm just starting with Android and I have no experience with Java what so ever. Anyhow, all I have is a timer and a button. Obviously the button starts the timer which counts down from 60 ( 1 minute ) and then vibrates when it's done. All worked fine up until the point I decided to press the lock screen button to put the phone to sleep. I found out that the timer in my app stops going until I unlock the phone. This also happens if I set the auto sleep time to less than 60 seconds and the phone falls asleep on it's own. My question is - how can I have that chronometer running even when the screen is not active?

You need to make this using BroadCastRecievers for system-calls. (Related Helpful question)
You can also play off the life-cyles of the Activity using the PowerManager.
Example using PowerManager:
#Override
protected void onPause()
{
super.onPause();
// If the screen is off then the device has been locked
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
boolean isScreenOn = powerManager.isScreenOn();
if (!isScreenOn) {
// The screen has been locked
// Continue your timer
}
}

Related

Android service with a TimerTask and a WakeLock pauses its work when screen is off

Hello to all Android developers,
I wish to ask a question about something that drives me mad over the last few weeks and I cannot make it work properly.
I have an Android app that runs a service that has a loop in it that runs every few seconds and should run endlessly and never stop, not even if the screen is off. this service will run regardless of the app's UI being open or not. it runs even if the task stack was cleared.
I implemented all that by using a service and a TimerTask inside the service class, like this:
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
public void run() {
//Do something that will run again and again every time that the timer is called. every 10 seconds.
}
};
timer.schedule(timerTask, 1000, 10000);
I added a WakeLock inside this loop (And I also tried to run the WakeLock only once outside of the loop):
PowerManager mgr = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "myapp:MyWakeLock1234");
if (!wakeLock.isHeld()) {
wakeLock.acquire();
Log.d("WAKEWAKE", "WAKELOCK ACQUIRED NOW...");
}
I never release the WakeLock because the service loop runs infinitely even with the screen off.
Inside the timer's loop I also added a MediaPlayer sound that will beep every few seconds (For testing purposes - I intent to remove it if all works o.k):
MediaPlayer mp = MediaPlayer.create(MyService2.this, R.raw.beepbeep);
mp.setOnCompletionListener(MediaPlayer::release);
mp.start();
The service itself runs fine and I also set the app to reload the service after BOOT and it works fine also.
The only problem that I have is AFTER I switch the phone's screen off using the power button or whenever the screen switches off on any circumstance - and then the timer keeps on running and the beep keeps on playing for every 10 seconds and then... STOPS !
It may stop for few minutes, it may stop for 20 minutes, it will resume beeping when the screen is off (WakeLock) after that for 1 or more times and AGAIN. Stops for another N minutes.
Once I open the phone's display to go out of wakelock - the loop magically resume running every 10 seconds and beeping well like there is no problem !
I tried everything ! I tried to remove the MediaPlayer beeps, tried to run the WakeLock only once and not in a loop, tried to make a lousy loop instead of using a TimerTask. Everything works well until the screen turns off ! it looks like my service gets into some sort of sleep mode or pause.
I even tried to download a piece of code from GitHub that claims to work well, but it stops/pauses exactly the same way !
I have to comment that the TimeTask is EMPTY at this point and runs nothing except from the WakeLock code and the MediaPlayer beep. No communication, no nothing !
What can I do about it to solve this problem ?
Thank you for your kind answers ! I appreciate it !

Should the Service be stopped when not in use?

I am coding an application which will trigger some action (like toast message) every 5 minute after the Screen is ON. I have made a 'Service' for this purpose. My Service is running successfully and triggering the specified action every 5 minutes.
My 'Service' keeps on running even when the Screen is OFF. I don't want to perform any action when the Screen is OFF. Should I stop the service on every screen OFF and re-run it on the next screen ON? or should I keep it running even when the Screen is OFF?
I just want to decrease the load on CPU performance because of the background running 'Service'.
Let the service keep running, and display the Toast only if the screen is off using following code,
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
boolean isScreenOn = pm.isScreenOn();
Now,
if ( isScreenOn )
{
// Display Toast
}
else
{
// Do nothing
}

Service of an app stops when phone is not being charged

My Activity starts a service by calling startservice(). To simplify my problem lets say the service will be a counter, and the counter will be increased in every 10 sec.
Timer t_counter;
int counter = 0;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
t_counter = new Timer();
t_counter.schedule(new TimerTask() {
#Override
public void run() {
counter++;
Log.d("counter: ",Integer.toString(counter));
}}, 0, 10000);
return Service.START_STICKY;
}
When the phone is being charged, (or in debug mode - since I can see the the Logcat) the service works as expected. In around every 10 sec Logcat shows the debug info, whenever the app is in background or not. But when I have unplugged the phone, the service stops running after a while. Event when the app (Activity which started the service) is active. Note that service not destroyed, just put on hold, or something like this.
Because when I plug in the mobile again, the timer continues and the value of the counter is being increased from the value where I just unplugged the phone. So if the service has been destroyed then value would have been zero again. (also I debugging the lifecycle of the service, and cannot see onStartCOmmand(), onDestroy() would have been called )
I have searched solutions for it, but I think I have not het the right answer for this behavior.
I know that I should use AlarmManager instead of Timer. Or it would also work if I put the service foreground by startForeground(), or maybe separate process would solve this problem. But I would like to know why my solution is working with charging. Also where can I find infos about this "idle" state of a service. (not executing timer schedules, but not destroyed) Thanks!
You need to hold lock if your service has to be running in the background
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl =
pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
wl.acquire();
// when you done
wl.release();
Better way is to use AlarmManager because keep the service running all the time will drain the battery and waste the system resources.

App seems to stop working when the screen goes to sleep

I have a CPU intensive long-running operation (a few hours) that I am using AsyncTask to perform. As it continues, it updates a progressbar on the screen to show what percentage of the task is done.
I discovered that when my screen goes to sleep (time-out) the task seems to stop. Not sure whether this is happing because the AsyncTask stops or it gets stuck at trying to update the screen (latter I am thinking).
Other than never letting the screen sleep, how else can I prevent my AsyncTask to stop executing? And if that is the only way, then how do I make sure that the screen doesn't sleep?
EDIT: I must add that I know this sounds like a non-user-friendly app as commented by someone below. This does a very specialized task (processes thousands of image files to compare processing on different systems) and is to be used by a few users internally, not for public release.
That's expected behavior. The idea is that the phone's battery is not supposed to drain because of bad apps. If the screen is off, the user generally expects the phone to sleep.
If you need your app to run, you can use a WakeLock to keep the phone running (with the screen off): Documentation here and here.
Note that a wake lock requires the WAKE_LOCK permission, and again, you need to make it clear to the user that your app will drink the phone's milkshake while it's off.
Not sure if anyone will read this as the OP is several years old but I am in the same boat in that I need to use a wakelock for an app for internal use, and leaving the screen on was not ok (I just needed the cpu on so I could run some metrics queries) I simply used a partial wakelock; ie:
public class my_frag extends Fragment {
WakeLock wl;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
setRetainInstance(true);
PowerManager pm = (PowerManager) this.getActivity().getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
//I happen to have it in a button click event based on an async task
//Side note: I should probably be using a Loader for my Async task but this works fine
connectButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (metrics_task != null)
{
Status s = metrics_task.getStatus();
if (s.name().equals("RUNNING")){
if (metrics_task.running){
metrics_task.cancel(true);
connectButton.setText("Start");
metrics_task.running = false;
wl.release(); <--releases it on async stop
}
else{
metrics_task = new start_metrics(ae);
metrics_task.execute();
wl.acquire(); <--starts it on async start
}
}
else{
metrics_task = new start_metrics(ae);
metrics_task.execute();
}
}
else{
metrics_task = new start_metrics(ae);
metrics_task.execute();
}
}
});
This worked great with no issues
My 2 cents on this old post, in case it might help someone. If all you want is to prevent your screen from going to sleep, there's a simple solution that does not require a permission from the user - and it's just 2 lines of code:
// prevent the screen from sleeping
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// do your stuff
// don't forget to re-enable the screen time-out so it won't stay awake from now on
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
An important note: it can only be called within an Activity - not from other app components. more details can be found here.

Android: Wakelock & handling orientation change

I'm using Wakelock in my application to prevent the phone from sleeping when the app is visible.
The problem comes when there is an orientation change and the system destroys and re-creates the app in landscape mode. If the wakelock timer has expired in the background the system takes the release of wakelock as an opportunity to switch off the screen.
Edit: I should mention that I am setting Wakelock onResume, and releasing onPause - as I understand it, it's necessary to release then to prevent the app from leaking the wakelock.
I need wakelock to continue through the orientation change.
Below I've outlined a solution to this. Is this the preferred way to handle it, and are there any alternatives?
Create a service which holds wakelock (rather than the activity) and when the activity unbinds the service starts a countdown timer (for say 10 seconds) in which it will release wakelock when the timer expires if the activity does not rebind. If it was a simple orientation change the activity will rebind within that 10 seconds and so maintain wakelock, if it doesn't, wakelock will be released.
Thanks.
Instead of a WakeLock, try getWindow().setFlags() using the WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON flag.
If the wakelock timer has expired in
the background the system takes the
release of wakelock as an opportunity
to switch off the screen.
It shouldn't. By definition, the user has interacted with the device, so the screen should stay on for that reason, independent of anything else.
Here's how I did it...
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK|PowerManager.ON_AFTER_RELEASE, "DoNotDimScreen");
Followed by...
wl.acquire();
... when you need to actually activate the wake lock.
The 'PowerManager.ON_AFTER_RELEASE' flag pokes the user activity timer so the screen stays on for a little longer when this wake lock is released, which will be the case when your activity is Destroyed on a change of orientation.
Works OK for me!
I did it by actually never releasing the wakelock. Instead, I acquire it with timeout.
private PowerManager.WakeLock wl;
protected void onStart(Bundle savedInstanceState) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "Words counter");
// disable reference counting, as acquire/release calls are not paired
wl.setReferenceCounted(false);
wl.acquire();
}
protected void onStop() {
// acquire for few seconds to keep lock until onStart is called with new orietnation
wl.acquire(3000);
}
Advantages over other methods:
Usable with the SCREEN_DIM_WAKE_LOCK
Simple (no need to play with isFinishing() etc.)
Does not poke user activity after orientation change. I.e. dimmed display stays dimmed
If you release (e.g. the time is over but the user remained in the activity), it's released immediately. No need to wait for default timeout.

Categories

Resources