Android: is there any additional information from Intent.ACTION_TIME_CHANGED? - android

Is there any additional information available from Intent.ACTION_TIME_CHANGED? There's nothing in getData() or getExtras().
I would like to know:
The time phone had before setting new time;
Who has changed the time: the user (manually) or the phone carrier?
Any other way to get those informations are welcome!

I looked into source code of Android and this broadcast doesn't have any extras. So, there is no way to learn this info.

You can do one thing if the accuracy of previous time is not that important. You can get the previous time with +/- 1 minute accurate by following way..
Register for broadcast action ACTION_TIME_TICK (This will be broadcasted every minute).
When ever the time ticks, if there is a difference of more than 1 minute between your current time and last tick time, you can infer that there occured a time change. After that you just update the new time to shared preference. Thats all.
Register for ACTION_TIME_TICK broadcast.
When broadcast received :
2.1 If first time broadcast, Enter the current system time to Shared Preference.
2.2 else compare the current time with previously entered time and if occurs a difference of more than 1 minute, means the time time has changed. Then update the new system time to SP.
Happy coding.

I don't think getting the why the time changed is possible, though finding out the amount the time was changed should be possible by comparing System.currentTimeMillis() to the SystemClock.elapsedRealtime(), since SystemClock.elapsedRealtime() does not get adjusted in this case.
An example would be something like:
private long realtimeOffset = System.currentTimeMillis() - SystemClock.elapsedRealtime();
private void onReceive(Context context, Intent intent) {
if(Intent.ACTION_TIME_CHANGED.equals(intent.getAction()) {
long prevRealtimeOffset = realtimeOffset;
realtimeOffset = System.currentTimeMillis() - SystemClock.elapsedRealtime();
Log.i(TAG, "Clock was adjusted by: " + (realtimeOffset - prevRealtimeOffset) + " ms");
}
}

Related

Best way to reset a database value every week on specific day (Android - Room)

I'm working on an Android app that has a functionality that is weekly basis, that is, every day of the week the user has to mark as done the day. This value is a boolean on my database, that is initialized with false, and is set to true when the user clicks on the checkbox. Everything is working fine.
But my problem is that I need to "reset" this boolean value to false on all the seven days of the week every time a new week begins. I don't need to have records of the past weeks. All that matters is the actual week (Sunday to Saturday).
It's a very simple task, I only need to do this:
for(WeekDay day: dao.getWeekDays()){
day.setDone(false);
dao.updateWeekDay(day); //update the value in database
}
So, I did some research (I'm new to android) and find out that Android has different schedule services like JobScheduler or AlarmManager. My app is designed to Android 10+ (API 29+).
What do you think is the best solution for my problem?
It's a very simple task (it won't take too much battery, internet,...) and I need to do this in a specific day (Sunday) every week. Also, this task needs to be done as soon as it possible, even if the phone is turned off on Sunday. It doesn't need to be a background service, but I need to guarantee that when the user opens the app and it's a new week, that method needs to be call before, but only if it had not been call in the actual week before.
Anyone has ideas?
Ok, I think I found a simple solution for my problem, based on other similar answers I read. I just need to run these function every time the app starts. I didn't need to use any background service, like WorkManager.
I only need to store in SharedPreferences the last date when the system did a reset in the values. Then, every time I open the app, it checks if today is in a different week from the last reset day. If it's true, then I run that "for cycle" in the question and update the last reset day to today in the SharedPreferences. If it's false, I do nothing.
The method inSameCalendarWeek checks if the day is in the same week from the same year of today (Locale.US guarantees that a week starts on Sunday. But I could change that to Locale.getDefault() to be more flexible). Also, for example, if December 31 is in the same week of January 1, even if they are in different years, the method will return true.
private void checkAndResetDoneDays() {
long lastResetDay = settings.getLong(LAST_DAY_RESET, 0);
LocalDate date = Instant.ofEpochMilli(lastResetDay).atZone(ZoneId.systemDefault()).toLocalDate();
if (!inSameCalendarWeek(date)) {
resetDoneDays();
settings.edit()
.putLong(LAST_DAY_RESET, LocalDate.now(ZoneId.systemDefault()).atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli())
.commit();
}
}
public boolean inSameCalendarWeek(LocalDate firstDate) {
LocalDate secondDate = LocalDate.now(ZoneId.systemDefault());
// get a reference to the system of calendar weeks in US Locale (to guarantee that week starts on Sunday)
WeekFields weekFields = WeekFields.of(Locale.US);
// find out the calendar week for each of the dates
int firstDatesCalendarWeek = firstDate.get(weekFields.weekOfWeekBasedYear());
int secondDatesCalendarWeek = secondDate.get(weekFields.weekOfWeekBasedYear());
/*
* find out the week based year, too,
* two dates might be both in a calendar week number 1 for example,
* but in different years
*/
int firstWeekBasedYear = firstDate.get(weekFields.weekBasedYear());
int secondWeekBasedYear = secondDate.get(weekFields.weekBasedYear());
// return if they are equal or not
return firstDatesCalendarWeek == secondDatesCalendarWeek
&& firstWeekBasedYear == secondWeekBasedYear;
}

How to create an alarm which will be called after several months?

I've just learned about the AlarmManager and tried to play around with it. As I understood the alarms are set by saying that it needs to be called after X miliseconds like in the code below:
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (sec * 1000), pendingIntent);
However, I'm concerned about the performance of system when it comes to long periods of time.
If I need to set alarm that will activate notification say after 10 months, what should I do? Do I need to convert needed period of time into miliseconds and pass it in the same way? Or there are other more efficient ways to work with long periods of time?
Yes, you have to pass it as milliseconds. I'm not sure why you're concerned about performance from that, there's no loss in performance form passing a large value instead of a small one. Your only real problem is that doing in X months, the length of a month isn't regular. I'd create a Calendar object for the end time and convert that to milliseconds to get it right.
Use like this
int month = 2;
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),AlarmManager.INTERVAL_DAY * 30*month, pendingIntent);
How to set alarm for long duration has already been discusses above.
You just need to keep a check that if device gets restarted you reset your alarm because alarms gets canceled once system goes off.
link here

Calculate start time for the repeated AlarmManager

I'm working on an Android application which uses AlarmManager as follows:
Long startTime = Calendar.getInstance().getTimeInMillis();
alarm.setRepeating(
AlarmManager.RTC_WAKEUP,
startTime,
15* 60 * 1000,
PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT));
I want to calculate the startTime. Let's say I need to run some code repeatedly after 15 minutes, but this after 15 minutes should not start from now (current time) but right from the next slot. Whenever I enable the alarm it should start it from the next available slot (which means I need to calculate the start time).
Example 1: If current time is 10:8, then the first run should be at 10:15.
Example 2: If it's 10:17, then first the run should be at 10:30.
Example 3: If it's 10:38, then the first run should be at 10:45.
As AlarmManager takes 2 time parameters in milliseconds, the first one when to start the alarm and the second as the repeat time in milliseconds (15 minutes).
If it's still unclear then I would say I need to run my code when minutes of the device are either one of the following values:
00, 15, 30, 45 irrespective of the hour value of the device.
First, bear in mind that Doze mode and app standby on Android 6.0+ will mean that you will not always get control when you want.
That being said, you need to adjust startTime. Call get(Calendar.MINUTE) on it to get the current minutes. Determine how many minutes you need to add to get to the next quarter-hour. Then, call add(Calendar.MINUTE, ...), where ... is the amount you need to add to get the minute value to the next quarter-hour. Using add() will handle incrementing the hour, day, etc. as needed.

Android system time

in my application i need to get current Date and time, every time the user inputs data with it.
I know i can use System.currentTimeMillis(), but it can give me wrong time(because it gives system time, witch can be edited by user)
So i see the only way is to call server for current time, when the user makes data input. but i am not sure that internet connection is always awailable.
Is there any way to get current time (not system time) in android, without using internet connection?
If you don't want system time you need some other source then.
There are a few possibilities that I know:
Get it from web - Internet needed
Get it from router - enabled wifi needed (NTP)
Get it from GPS - GPS fix needed
All of these aren't very helpful I believe. I don't think you can find a way of getting current time without connecting so something externally.
In my opinion you should use system time and assume it's set correctly. When it's not your application shouldn't crash and should gently know user that he has wrong content because of wrong dates ...
I believe there's no way to get the current system time without the timezone.
A good approach would be getting the current system time first
long time= System.currentTimeMillis();
And then getting the correct TimeZone to handle it
Calendar cal = Calendar.getInstance();
TimeZone tz = cal.getTimeZone();
long dateInMillis = System.currentTimeMillis();
String format = "yyyy-MM-dd HH:mm:ss";
final SimpleDateFormat sdf = new SimpleDateFormat(format);
String dateString = sdf.format(new Date(dateInMillis));
Use dateString as your variable which contains current date time as timestamp.
Well, I googled about your topic, and i got logic solution but not tested:
" Use The network-provided values ", in the android phone settings, it;a as shown in the picture bellow:
The screen I show is DateTimeSettings. The checkbox "Use network-provided values" is associated to the shared preference String KEY_AUTO_TIME = "auto_time"; and also to Settings.System.AUTO_TIME
This settings is observed by an observed called mAutoTimeObserver in the 2 network ServiceStateTrackers: GsmServiceStateTracker and CdmaServiceStateTracker.
Both implementations call a method called revertToNitz() when the settings becomes true. Apparently NITZ is the equivalent of NTP in the carrier world.
Bottom line: You can set the time to the value provided by the carrier thanks to revertToNitz(). Unfortunately, I haven't found a mechanism to get the network time. If you really need to do this, I'm afraid, you'll have to copy these ServiceStateTrackers implementations, catch the intent raised by the framework (I suppose), and add a getter to mSavedTime.
For more informations, i suggest you to check this link here
Use the ScheduledExecutorService with scheduleAtFixedRate to send you "clock ticks". If the user initiates an event and the number of accumulated "clock ticks" since the last event doesn't match the time change on the system clock, you're being lied to.
You don't need to know the correct time. You need to know the correct interval. This can be done with any periodic source, even a local one. (Timekeeping is two jobs: a metronome and a labeler for the intervals of the metronome. You don't want the system's labels because they can be made to lie, but the metronome ticks on even if the labels are changed.)
I'd recommend a relatively slow tick rate (<= 1 tick per minute) and rather sloppy comparisons (within 2%, maybe) since the various clocks may not be all that accurate.

How android calender setInexactRepeating works?

I am developing small android application. And I want to do something in my application after some minutes. These minutes are not static one these are dynamic ones.
So i am using android calender setInexactRepeating for this.
My code looks like this
Calendar cal = Calendar.getInstance();
// Start something after 4 minutes
cal.add(Calendar.MINUTE, 4);
get_alaram_service().setInexactRepeating(AlarmManager.RTC_WAKEUP,
cal.getTimeInMillis(), 1000*300, get_pendingintent());
So this will work setInexactRepeating after 4 min it will run my pending intent and after that it will keep repeating this for this much amount of time. (1000*300).
So my problem is that in setInexactRepeating 2nd parameter is for at what time I want to start my timer and 3rd parameter for repeating this thing. Now 2nd parameter tales value in milisec. I tried to pass my own value of minutes in milisec like(1000*300) then its not working properly. I don't how its working properly. When I checked cal.getTimeInMillis() it is very big integer number. what is that actually.
Am i doing something wrong need your help thank you...
Although this isn't explicitly stated in the documentation the second parameter (triggerAtMillis) is time in milliseconds since the Epoch. This is what Calendar.getInstance() returns. Calling this method will return the current time. This is a big number, since it is actually the number of milliseconds after 1/1/1970. You then need to add something to it (e.g. 4 minutes) to define when the AlarmManager will first fire.

Categories

Resources