Android: keep timer running when app closed - java

My app needs to update its data every 24hrs. The user should not be able to access some parts of the app if its out of date.
When the app starts up, I check if the database is out of date. But, the users might keep the app open of in the background for a long time, and I need to alert them when the update is required.
What's the best way to do this? My Initial thought was to use some kind of Handler thread and save a timestamp somewhere every time the app was paused, and then calculate the new time and restart the timer on resumer.
This leaves two questions:
How can I detect whenever my app is paused or resumed, regardless of activity?
And what is the best idiom for a long-running timer in Android? (keeping in mid that it has to be able to modify UI components ie show an alert when he time is up)

You could do that, but you should not, instead store the time stamp in the shared preferences whenever the app get closed, when open again read that value again and calculate the difference by getting the actual timestamp.... then after that update if necessary the lapsed time!
timeStamp is just a long value..
and you can get it by just calling the System.currentTimeMillis()
and for the shared preferences use the Class SharedPreferences

You can have a Service do the query every 24 hours for you and notify the user if it fails. You can use the AlarmManager for that. Eg:
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent m_intent = new Intent(this, YourService.class);
PendingIntent pi = PendingIntent.getService(this, 2, m_intent, 0);
alarm.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 1000 * 24 * 60 * 60, pi);
The Service can then ask the AlrmManager to call itself after 24 hours again using the above code only.
NOTE: Alarms can be cancelled by the system or the user (force stop). So, this solution comes with its caveats.

Related

How can i run my alarm when the app is completly closed in Android (Kotlin)

Im creating a custom alarm app, and this means i have to run a piece of code (for example calling an Intent so it open a screen where i can stop the alarm). What is the best way to achieve this?
I tried it with the Alarm Manager and used
<receiver android:name=".receiver.AlarmReceiver"
android:process=":remote"></receiver>
in the Manifest File
In my code i call this
var alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0)
alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 10000, pendingIntent )
10000 because i wanted to test it, if it gets called after 10s
Is this the best way to do an alarm clockapp?
simple "yes" is too less for answer on SO, so I can only add that exact alarms are draining battery more than inexact, so use both types with respect to user. still, for alarm clock app broadcast calls should be exact, so go on with that solution
also, from doc:
Note: The Alarm Manager is intended for cases where you want to have your application code run at a specific time, even if your application is not currently running. For normal timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.
and also note a change since API19 (if you want to support such old):
Note: Beginning with API 19 (Build.VERSION_CODES.KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, android.app.PendingIntent) and setExact(int, long, android.app.PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.

Scheduling a notification?

Is there any way to schedule a notification to appear at a specific time?
I am developing an app that reminds a user to change their bandage every 6/12 hours and I wish to send a notification to the user 6/12 hours after they confirm that they have applied the bandage.
Is there any way to do this? I have tried to implement the alarmManager Class however every example I have found uses a specific time of the day as opposed to 6/12 hours after an event.
I have an app which checks whether to show a notification every 24 hours. You can change it to whatever interval you would like.
with(context.getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
// Create a PendingIntent which AlarmManager would raise.
// You should have a BroadcastReceiver to receive the intent and send a push notification.
setInexactRepeating(
AlarmManager.RTC_WAKEUP,
startAt.toEpochSecond() * 1000,
intervalInMillis,
pendingIntent
)
}
startAt -> Epoch when your alarm should start working (preferably in future). If this is in past, it will immediately boradcast the intent.
intervalInMillis -> Interval in milliseconds. For your case this should be 6 hours.
If your app requires different alarms (notifications) at 6 and 12 hours, I would still go with 6 hours or even 3 hours as the interval. When the broadcast is received, you should check if the app is supposed to send a notification or not. If not, don't do anything.
Read more about Scheduling repeating alarms.
Note: AlarmManager is affected by doze mode and you need to reset all your alarms after the phone restarts. Clubbing this with WorkManager would be ideal. But this should get you started.
Schedule tasks with WorkManager
https://developer.android.com/topic/libraries/architecture/workmanager/
Previously firebase-jobdispatcher-android was working fine now google introduced new WorkManager for scheduling task.
Here is a simple implementaion
http://thetechnocafe.com/how-to-use-workmanager-in-android/

Timing for Android GPS logging is inaccurate

In my app I am trying to get the users current location and log it. The user can select an interval. Right now the logging is not happening consistently. Sometimes the logs are just off by a couple seconds and sometimes they are off by a few hours. Also if it is not logging and you turn the GPS off/on then it will start working again. The entire app is based around the idea that you will only be able to get your location using GPS when you use it. I have a few theories as to why this may be.
I am getting the logs by using AlarmManager setExact inside a broadcast receiver. I know that this is not guaranteed to be perfectly accurate and could possible account for a few seconds here and there.
I also know that the GPS can take some time to acquire. Is there a normal range for this time. I could see this taking up to a few minutes possibly but several hours seems like a lot.
I don't know a lot about loopers and am having some difficulty understanding them. I was wondering if the looper in the requestSingleUpdate could have anything to do with it
locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, this, Looper.myLooper());
I know loopers process tasks in the background using a queue and I was't sure if other tasks could get stuck on the queue in front of it causing delays.
My last theory is that it has something to do with not timing out while searching for the GPS signal. If I am searching for a signal every 10 seconds (the fastest allowed) but the phone cannot find a signal the AlarmManager will fire again and I will have two services trying to get a signal. I don't really understand how the services work under the hood so I don't know if this is a possibility or not.
If anyone has any ideas/resources and could point me in the right direction I would really appreciate it.
Here is the code. I can include more if that would be helpful.
#Override
public void onReceive(Context context, Intent intent) {
SharedPreferences pref = context.getSharedPreferences(SettingsActivity.PREFERENCES, Context.MODE_PRIVATE);
if(!pref.getBoolean(SettingsActivity.ARG_TRACK, true)){
return;
}
alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent alarmIntent = new Intent(context.getApplicationContext(), AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
long interval = pref.getLong(SettingsActivity.ARG_TRACKER_INTERVAL, 15000);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarmMgr.setExact(AlarmManager.RTC_WAKEUP,System.currentTimeMillis()+interval, pendingIntent);
}else{
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
}
context.startService(new Intent(context.getApplicationContext(), AlarmService.class));
}
Inside my service I am calling LocationManager requestSingleUpdate()
locationManager.requestSingleUpdate(LocationManager.GPS_PROVIDER, this, Looper.myLooper());
In my app I am trying to get the users current location and log it. The user can select an interval. Right now the logging is not happening consistently. Sometimes the logs are just off by a couple seconds and sometimes they are off by a few hours. Also if it is not logging and you turn the GPS off/on then it will start working again. The entire app is based around the idea that you will only be able to get your location using GPS when you use it. I have a few theories as to why this may be.
If i'm not wroing, in your scenario, the interval is not period of location provider. It's directly period of alarm. The story like that
User selects an interval(period), for example 10 minutes.
After 10 minutes(approximately), device wakes up and makes location request to receive single location.
In that case you are facing the gps provider's lag. So, each time when wake up, you are waiting the gps provider to be warm. This is why the logs aren't consistently.
I am getting the logs by using AlarmManager setExact inside a broadcast receiver. I know that this is not guaranteed to be perfectly accurate and could possible account for a few seconds here and there.
You are using exact settings for wake up. This is not actual reason of long lag.
I also know that the GPS can take some time to acquire. Is there a normal range for this time. I could see this taking up to a few minutes possibly but several hours seems like a lot.
You have to wait until GPS provider to be warm. This warming time could change by where you stay at this moment. If you are inside a building, takes long
I don't know a lot about loopers and am having some difficulty understanding them. I was wondering if the looper in the requestSingleUpdate could have anything to do with it
Simply, when you pass a thread's looper here, onLocationChanged() method will be used the looper. But you are already making single request. No more update will be fired. (In your scenario, each wake up is one single location request)
My last theory is that it has something to do with not timing out while searching for the GPS signal. If I am searching for a signal every 10 seconds (the fastest allowed) but the phone cannot find a signal the AlarmManager will fire again and I will have two services trying to get a signal. I don't really understand how the services work under the hood so I don't know if this is a possibility or not.
This is a problem of your scenario. If you set alarm with short period, it's so normal the next wake up could happen. You can follow below things
Due to wait until gps warm, make long alarm period at least 5 minutes
Make timeout scenario, for example wait 1 minute or more until receiving location.
If cant receive location in time, shutdown everything and wait the next wakeup.

How to restrict the Android application to run only a certain time period?

I want to create an application that runs for a certain time interval.
[EDITED] By certain time interval, I mean if a user downloads an application from the play store. He can review all the features and functionality for a fixed period of time let say X hours only. After that, we can put any kind restriction (any UI/Navigation restriction so that user cannot review the features).
[The Problem]
what is the easiest as well as an efficient way of doing it? Like I don't think these solutions will work:
Calendar c = Calendar.getInstance();
int seconds = c.get(Calendar.SECOND);
Or
Time now = new Time();
now.setToNow();
What is the best way of putting restrictions (application side or server side as I have seen in some of the game application, where a synchronization is made between a server and application so that user cannot simply change the time and access the features).
So if you want to run your application for a certain period of time in the first run you need to keep a track if its a first run. So you might take set a preference variable so that it can tell you that if its a first run or not.
Now set a CountDownTimer and set it to run for an hour and when the timer is finished, close the Activity by calling finish() to it.
SharedPreferences pref = getSharedPreferences("ApplicationTag", Activity.MODE_PRIVATE);
if (pref.contains("FIRST_LAUNCH")){
finish(); // As you want, it can't be used if the application launches second time.
} else {
// Set the first launch flag to true.
pref.edit.putBoolean("FIRST_LAUNCH", true).commit();
// Start the count down timer
new CountDownTimer(3600000, 1000) {
public void onTick(long millisRemaining) {
// Do nothing
}
public void onFinish() {
// Finish the Activity
finish();
}
}.start();
So you might thinking that what if I switch between Activities. So in that case, you make create a BaseActivity class which will be extended by other Activities in your application. Place the CountDownTimer code there and take a reference of the Context you're in then call context.finish() when the timer is finished.
So in case of you don't want to limit the user for first launch, you need to save the time somehow in your application. When the Activity is finished, you'll get the callback in onDestroy function. So override the onDestroy function and set some preference again with the remaining time in mili seconds. So that you can initialize the timer again when the application starts.
Hope that helps!
Try setting an Alarm for firing any activity after any amount of time you want. Like following:
calendar = Calendar.getInstance();
Intent intent = new Intent(this, ActivityYouWantToStart.class);
PendingIntent pIntent = PendingIntent.getBroadcast(this, 101, intent, 0);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
calendar.add(Calendar.Hour,1);
alarm.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pIntent);
Call this code when user launches your code for first time and inside ActivityYouWantToStart.class do whatever you want to do after such amount of time.

AlarmManager skips alarms set using set() / setExact() in a 48hrs+ cycle

In an app I have to regularly sync data to a server which happens at a fixed interval (mostly) of 5mins.
I am using set() / setExact() depending upon if Build API >= 19. Now, for most of the time the alarm gets fired and does it's job but intermittently (even during daytime) the alarm isn't getting fired.
The alarm manager is passed a pendingIntent for an IntentService which does the sync work.
And in onHandleIntent I am also running my setSchedule() which in turn sets an alarm to get fired after 5 mins(same as above^).
Using Alarm Type of RTC_WAKEUP (until now; I've recently changed it to elasped realtime + wakeup and waiting on for some test results)and the HTTP connection and socket timeout of 30secs each. The device was not restarted in between the 48hrs+ (as a sample case) duration as I don't miss any captured data it's just that the sync alarm skips somehow.
I am starting to doubt if this is a wakelock issue :|
Has anyone faced any problem with Kitkat's setExact() ? AFAIK, the way it is (except for using the RTC/elasped realtime change) the current way shouldn't be skipping on the alarms.

Categories

Resources