I've a program which includes service. This program has settings which allows user to set up, disable and enable time. Between these two times (if option is enabled of course), the program should not work.
I'm actually having hard time to do this. I've already sucessfully converted "disabled" and "enabled" time in milliseconds. I have following code but it doesn't work as expected. I want to detect if current time is between two set up times, so i can disable service at that time.
public boolean isCurrentTimeBetween_enableDisable() {
long sysTime = System.currentTimeMillis();
if((sysTime > disableTime && sysTime < enableTime)) {
return true;
}
return false;
}
Anyone can give me better hint?
UPDATE:
If user selects lets say
Disable hour: 15:00
Enable hour: 22:00
Then code work as expected.
But if user selects lets say:
Disable hour: 22:00
Enable hour: 06:00
Then its obviously that Enable hour is the NEXT day. So i wrote the following code:
if(todaysDisableDate(context).getTime() > enableAt.getTime()) {
enableCal.add(Calendar.DAY_OF_MONTH, 1);
enableAt = formatEnableDate.parse(enableCal.get(Calendar.DAY_OF_MONTH) + "-" +(enableCal.get(Calendar.MONTH)+1) + "-" + enableCal.get(Calendar.YEAR) + " " + endHours_string + ":" + endMinutes_string);
}
Code below is getting the actual date.
public Date todaysDisableDate(Context context) {
Calendar disableCal = Calendar.getInstance();
getTimeValues_preferences((ContextWrapper) context, true, false); // this only gets a string for hour and minute (which is set up in preferences )
Date disableAt = null;
try {
disableAt = formatDisableDate.parse(disableCal.get(Calendar.DAY_OF_MONTH)+"-"+(disableCal.get(Calendar.MONTH)+1)+"-"+disableCal.get(Calendar.YEAR)+" "+startHours_string+":"+startMinutes_string); // današnji datum z današnjo uro
} catch (ParseException e) {
e.printStackTrace();
}
return disableAt;
}
public Date todaysEnableDate(Context context) {
Calendar enableCal = Calendar.getInstance();
getTimeValues_preferences((ContextWrapper) context, false, true);
Date enableAt = null;
try {
enableAt = formatEnableDate.parse(enableCal.get(Calendar.DAY_OF_MONTH)+"-"+(enableCal.get(Calendar.MONTH)+1)+"-"+enableCal.get(Calendar.YEAR)+" "+endHours_string+":"+endMinutes_string); // današnji datum z današnjo uro
if(todaysDisableDate(context).getTime() > enableAt.getTime()) {
enableCal.add(Calendar.DAY_OF_MONTH, 1);
enableAt = formatEnableDate.parse(enableCal.get(Calendar.DAY_OF_MONTH)+"-"+(enableCal.get(Calendar.MONTH)+1)+"-"+enableCal.get(Calendar.YEAR)+" "+endHours_string+":"+endMinutes_string);
}
} catch (ParseException e) {
}
return enableAt;
}
Code is working fine if service starts before 00:00. But if the service starts after midnight (of next day), then i'm getting false from method isCurrentTimeBetween_enableDisable(), because methods todaysDisableDate(Context context) and todaysEnableDate(Context context) are pulling out the next day (the same day as system hour is in)
Do you have to compare dates in your code? If that's a project requirement then you can ignore the following.
Otherwise, I think you can use AlarmManager to create the feature without actually comparing the date. You can create a "Enable" intent and a "Disable" intent for the AlarmManager to fire at the scheduled time. Something like this:
Register your alarms when the user confirmed the time schedule.
Intent intent = new Intent(context, yourAlarmReceiver.class); //or implicit with action
PendingIntent pIntent = PendingIntent.getBroadcast(
context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.setRepeating (typeConstant, triggerAtMillis, intervalMillis, pIntent);
You just need to figure out what triggerAtMillis is to determine the first shot of that broadcast, and intervalMillis will be a full day, which is a constant in the AlarmManager class.
Setup your custom receiver class (which I wrote as yourAlarmReceiver) which should extend BroadcastReceiver, and register the receiver in your service. In the onReceive() you should perform the corresponding actions based on intent.getAction(). Don't forget to register your receiver with an intent filter if you want more customization.
#Override
public void onReceive(Context context, Intent intent) {
switch(intent.getAction()){
case "enable": //enable if not enabled
case "disable": //disable if not disabled
default: break;
}
}
In this way it may save you some time from struggling with comparing today and tomorrow. You can determine the time of the very first shot by getting the current system time, probably in 24-hour format, and determine if your intended time has already passed. Whether it's been passed, you just need to set the initial firing time to currentTime + difference.
Hope it will shed some light.
I would recommend you to use the start date and end date itself...and not convert them to miliseconds. But this is only if you're not sure.
private String compareStringOne = "9:45";
private String compareStringTwo = "1:45";
SimpleDateFormat inputParser = new SimpleDateFormat(inputFormat, Locale.US);
private void compareDates(){
Calendar now = Calendar.getInstance();
int hour = now.get(Calendar.HOUR);
int minute = now.get(Calendar.MINUTE);
date = parseDate(hour + ":" + minute);
dateCompareOne = parseDate(compareStringOne);
dateCompareTwo = parseDate(compareStringTwo);
if ( dateCompareOne.before( date ) && dateCompareTwo.after(date)) {
//This is where you determine if the date is inbetween
}
}
private Date parseDate(String date) {
try {
return inputParser.parse(date);
} catch (java.text.ParseException e) {
return new Date(0);
}
}
Related
So I encountered an issue on an Android 10 phone where deleted events are still present when I query the user's calendar. The problem persisted across several hours (3 at the time of writing this)
I've looked through the following posts already in an attempt to find solutions, but none of them seemed to have worked for me, and I'm not sure if I'm just implementing their solutions incorrectly, if something's wrong with the phone, or whatever else.
Here's the posts I mentioned above:
Calendar deleted event exists in cursor
Deleting events from Calendar not being deleted
Android CalendarContract, deleting a recurring event causes all events to disappear on calendar?
Querying android calendar retrieves even deleted events
I know that when a user deletes something off their calendar, there's a possibility of it hanging around in whatever DB or structure Android stores the events in with a dirty or deleted flag set. My problem is that the events are both still present, and have neither of the previously mentioned flags set.
Additionally, I know that it could be a sync issue between Google's calendar and whatever local datastore the events are being stored in, but this issue persisted on the phone I'm testing on even after pulling in newly created events from the user's calendar, which makes it seem to me that the local datastore and the calendar should be in sync.
Here's the full code for the file where this problem is occurring for me - some things may not be related to the issue but I'm including everything just in case.
package com.example.plumbingreportgenerator.util.calendar;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CalendarContract;
import android.provider.CalendarContract.*;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
public class EventReader {
// the context of the application this is being used in
private Context applicationContext;
public static final String[] EVENT_PROJECTION = new String[] {
Events.CALENDAR_ID, // 0
Events.TITLE, // 1
Events.DTSTART, // 2
Events.DELETED,
Events.DIRTY
};
// The indices for the projection array above.
private static final int PROJECTION_CALENDAR_ID_INDEX = 0;
private static final int PROJECTION_TITLE_INDEX = 1;
private static final int PROJECTION_DTSTART_INDEX = 2;
private static final int PROJECTION_DELETED_INDEX = 3;
private static final int PROJECTION_DIRTY_INDEX = 4;
public EventReader(Context context){
applicationContext = context;
}
// use android and java date libraries to determine the start of the month given by year and month
private static long getStartOfMonth(int year, int month){
java.util.Calendar cal = java.util.Calendar.getInstance();
cal.set(java.util.Calendar.YEAR, year);
cal.set(java.util.Calendar.MONTH, month);
cal.set(java.util.Calendar.DAY_OF_MONTH, 1);
cal.set(java.util.Calendar.HOUR_OF_DAY, 0);
cal.set(java.util.Calendar.MINUTE, 0);
cal.set(java.util.Calendar.SECOND, 0);
cal.set(java.util.Calendar.MILLISECOND, 0);
return cal.getTimeInMillis();
}
private static long getEndOfMonth(int year, int month){
java.util.Calendar cal = java.util.Calendar.getInstance();
cal.set(java.util.Calendar.YEAR, year);
cal.set(java.util.Calendar.MONTH, month);
cal.set(java.util.Calendar.DAY_OF_MONTH, cal.getActualMaximum(java.util.Calendar.DAY_OF_MONTH));
cal.set(java.util.Calendar.HOUR_OF_DAY, 23);
cal.set(java.util.Calendar.MINUTE, 59);
cal.set(java.util.Calendar.SECOND, 59);
cal.set(java.util.Calendar.MILLISECOND, 999);
return cal.getTimeInMillis();
}
// gets event titles for the given calendar from the given month
public ArrayList<EventTitleDateTuple> getEventDetailsForMonth(long calendarId, int year, int month){
// get the millisecond values for the start and end of the month given by year and month
long startOfMonth = getStartOfMonth(year, month);
long endOfMonth = getEndOfMonth(year, month);
// Create cursor and query for the events table
Cursor cur = null;
ContentResolver cr = applicationContext.getContentResolver();
Uri uri = Events.CONTENT_URI;
String selection = "((" + Events.CALENDAR_ID + " = ?) AND (" + Events.DELETED + " != 1) AND (" + Events.DIRTY + " != 1 ))";
String[] selectionArgs = new String[] {Long.toString(calendarId)};
// Submit the query and get a Cursor object back.
cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);
ArrayList<EventTitleDateTuple> eventDetails = new ArrayList<EventTitleDateTuple>();
while (cur.moveToNext()) {
long calID = 0;
String title = null;
long dtStart = 0;
// Get the field values
calID = cur.getLong(PROJECTION_CALENDAR_ID_INDEX);
title = cur.getString(PROJECTION_TITLE_INDEX);
int deleted = cur.getInt(PROJECTION_DELETED_INDEX);
int dirty = cur.getInt(PROJECTION_DIRTY_INDEX);
dtStart = cur.getLong(PROJECTION_DTSTART_INDEX);
// if the start date of the event is after this month and before the end of this month
if(dtStart >= startOfMonth && dtStart <= endOfMonth && title != null && title.length() > 0 && deleted != 1 && dirty != 1 && !title.contains("testy mates face")){
// the deleted events still make it through to here
eventDetails.add(new EventTitleDateTuple(title, dtStart));
}
}
cur.close();
return eventDetails;
}
}
This is not a problem with deleting events, it is problem with syncing. Sometimes in 2020/2021 Google added a "feature" (or a bug) in form of some kind of annoying cache.
In reality it means, from now on (unlike before) you simply never know if you have a fresh data or outdated data from their cache. The only way to somewhat force their cache to update regularly is to have constantly turned on auto-syncing of ALL CALENDARS, all the time.
This way changes take only seconds and Google Calendar cache is always being updated. If the auto-syncing of just 1 calendar is turned off, from unknown reasons cache is not updated on time and often it takes hours to reflect changes...
Similar problems can be find on these links:
Android CalendarContract.Instances table returns old values
Android Calendar Provider does not return latest data
Or even here on Google Support page:
https://support.google.com/calendar/thread/47536340?hl=en
I would love to know who in Google had this genius idea...Argh
im making an android app which shows time of upload relative to the device time, but if the device time and date is not set correct then I do not get the desired result. so how to show warning or error if the device time and date is not correct or matches to the internet time. the app should not work unless the user set the date and time correct.
Get an extra UTC DateTimeOffset parameter as a response from the uploaded API & then convert it into your local timezone.
Cons -
If time is set wrong in the device, you have to create a localization method for it which can convert the timestamp to proper time without interfering with the local timezone.
You can use static timezoneid for conversion or get it by internal API calls, I uses Xamarin soo for me it's like -
var timeZoneId = "Asia/Calcutta"; // use it for worldwide application usage TimeZoneInfo.Local.ToString();
DateTime localizedDateTime = TimeZoneInfo.ConvertTimeFromUtc(incomingDATE.ToUniversalTime(), TimeZoneInfo.FindSystemTimeZoneById(timeZoneId));
Soo convert the received UTC DateTimeOffset to Localized time.
This thing works best for my apps. I use jsoup to search the google time and gets current time and then I compare the phone time with google time. So if these time are different you can stop user using a dialogbox or alertbox to tell them the times have changed. You can implement in MainActivity to check this condition.
Here is a snippet so you get the idea more clearly.
public class HomeActivity extends AppCompatActivity {
//phoneDate and phoneTime to get current phone date and time
String phoneDate = new SimpleDateFormat("dd MMM yyyy ").format(clnd.getTime()).trim();
String phoneTime = new SimpleDateFormat("hh:mm a").format(clnd.getTime()).trim();
String googleDate;
String googleTime ;
#Override
protected void onCreate(Bundle _savedInstanceState) {
super.onCreate(_savedInstanceState);
setContentView(R.layout.home);
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
//URL to search time
String url = "https://www.google.co.in/search?q=time";
Document document = Jsoup.connect(url).get();
org.jsoup.select.Elements time = document.getElementsByClass("gsrt vk_bk FzvWSb YwPhnf");
org.jsoup.select.Elements date = document.getElementsByClass("KfQeJ");
Log.d("HTML", "google date" + String.format(date.text()));
Log.d("HTML", "google time" + time.text());
googleDate = date.text().trim();
googleTime = time.text().trim();
//'0'is not present when hour is single digit
char second = googleTime.charAt(1);
if(second == ':'){
googleTime = "0" + googleTime;
}
Log.d("Proper format", "google time" + googleTime);
Log.d("Date", "your current url when webpage loading.." + phoneDate);
Log.d("Time", "your current url when webpage loading.." + phoneTime);
if(googleDate.contains(phoneDate) && googleTime.equals(phoneTime)){
Log.d("Time", "your current url when webpage loading.." + " true");
}else{
Log.d("Time", "your current url when webpage loading.." + " false");
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}
}
I have this app release in Android that notifies the user everyday at specific time (for example 10:00 pm). I didn't use setRepeating as it was not recommended on higher APIs from 21 up. The following was the pseudo code I used to keep resetting the alarm.
AlarmController (set alarm)
Once time was met send to alarm receiver
Alarm receiver would call the Alarm Controller and Increase the day by 1 and set it again
At the same time Alarm receiver will fire up the Intentservice for notification and set notified **true** in DataBase
In theory it was supposed to work. I am using Joda Time here to easily increase the day by 1. But the problem was, the notification kept firing up at a random time, sometimes it will fire up 6, after it was last fire up, or most often every 1 hour or 30 mins. I don't get it. Now the pseudo code I provided was the basic one. On my real code I have two alarms, one for firing up the notification and set Notified to true and the other was to reset the notified to false once the day change.
My app has been released. I never expected this scenario to happen because the way I debug this was on genymotion, I move the time manually and everything seems to be working alright. I had to fire a log on fabric IO but it seems that the log would only show once you get an error. Anyone thanks
Here is my bare minimum code that I was using exactly:
Alarm Controller
public static void setAdaptiveReminder(Context context, long ALARM_ID, DateTime dateTime, boolean shouldsetAlarm) {
Intent myIntent = new Intent(context, AdaptiveReminderReceiver.class);
myIntent.putExtra("reminder", shouldsetAlarm);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, (int) ALARM_ID, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
ALARMMANAGER = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Log.d(TAG, "setAdaptiveReminder: " + dateTime.toLocalTime().toString() + " " + dateTime.toLocalDate().toString());
CrashUtility.LogErrorReportToFabric(TAG + " setAdaptiveReminder", dateTime.toLocalTime().toString() + " " + dateTime.toLocalDate().toString());
if (Utility.GetBuildVersion() >= 19 && Utility.GetBuildVersion() < 23) { // if lollipop
//ALARMMANAGER.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis() + 5000,1000,pendingIntent);
ALARMMANAGER.setExact(AlarmManager.RTC_WAKEUP, dateTime.toDate().getTime(), pendingIntent);
//ALARMMANAGER.setRepeating(AlarmManager.RTC_WAKEUP,dateTime.toDate().getTime(), AlarmManager.INTERVAL_DAY,pendingIntent);
} else if (Utility.GetBuildVersion() >= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//Log.d(TAG, "setTimeSinceLastUseReminder: android M and UP");
ALARMMANAGER.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, dateTime.toDate().getTime(), pendingIntent);
//ALARMMANAGER.setrep(AlarmManager.RTC_WAKEUP,dateTime.toDate().getTime(), AlarmManager.INTERVAL_DAY,pendingIntent);
}
}
AlarmPresenter
public void setAdaptiveReminder() {
//AlarmController.setAdaptiveReminder(context,778,d);
DateTime dateTime = TimeUtility.SetCorrectTimeInCorrectDate(settingsRepository.getAdaptiveReminderTime());
boolean isNotified = settingsRepository.isNotifiedReminder();
//Toast.makeText(context, "" + dateTime.toLocalTime().toString(), Toast.LENGTH_SHORT).show();
Log.d(TAG, "setAdaptiveReminder: gggfss " + TimeUtility.DateIsToday(dateTime) + " " + dateTime.toLocalTime().toString());
Log.d(TAG, "setAdaptiveReminder: " + isNotified);
if (TimeUtility.DateIsToday(dateTime) && !isNotified) {
dateTime = dateTime.plusDays(1);
CrashUtility.LogErrorReportToFabric(TAG + " setAdaptiveReminder", dateTime.toLocalTime().toString() + " " + dateTime.toLocalDate().toString());
AlarmController.setAdaptiveReminder(context, 778, dateTime, true);
Log.d(TAG, "setAdaptiveReminder: " + dateTime.toLocalDate() + " " + dateTime.toLocalTime().toString());
}
}
Receiver
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
this.context = context;
alarmControllerPresenter = new AlarmControllerPresenter(context,settingsRepository,habitRepository);
alarmControllerPresenter.setAdaptiveReminder();
}
So the code I have provided was the exact same code I am using to set the alarm every day. I just did some cleaning up and that was about it.
Hi this is my first time developing an simple Android-based application. I need to validate my starting time and ending time, which means ending time must not be less than or equal to starting time. I'm using an EditText to prompt a timepicker dialog. I had tried this code but it doesn't work, in terms of getting the error above at the line below
Date endTimeDate = format.parse(inputEndTime.getText().toString());
This is the whole code of the OnClickListener for EditText field to prompt out a timepicker dialog. I even tried to reverse the statements in if-else but it doesn't work for me too. Anyone can help me in this. Really thanks a lot!
inputEndTime.OnClickListener code:
inputEndTime.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
int hour = myTime.get(Calendar.HOUR_OF_DAY);
int min = myTime.get(Calendar.MINUTE);
TimePickerDialog myEndTimePickerDialog = new TimePickerDialog(ViewDocActivity.this,
new TimePickerDialog.OnTimeSetListener() {
#Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute)
{
SimpleDateFormat format = new SimpleDateFormat("HH:mm");
try
{
Date startTimeDate = format.parse(inputTime.getText().toString());
Date endTimeDate = format.parse(inputEndTime.getText().toString());
if (startTimeDate.compareTo(endTimeDate) <= 0)
{
Context timeContext = getApplicationContext();
CharSequence text = "Please enter the correct end time";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(timeContext, text, duration);
toast.show();
}
else
{
inputEndTime.setText(String.format("%02d:%02d", hourOfDay, minute));
}
}
catch(ParseException e)
{
e.printStackTrace();
}
}
}, hour, min, true);
myEndTimePickerDialog.setTitle("Select Time");
myEndTimePickerDialog.show();
}
});
The reason for your error is, that you are trying to parse the time from your EditText (inputEndTime), but that is empty at the time you do the format.parse().
As you set this up, you have an EditText and a TimePickerDialog. Now you are implementing the TimePickerDialog.OnTimeSetListener#onTimeSet() method. Here you get the time, the user selected in the dialog via the hourOfDay and minute parameters of the method. At this point you have the time, but it not yet written in the EditText field itself.
So the simplest solution to get your code working would be to set that time in your EditText field before doing anything further. To do so, add the following line as the first line of the onTimeSet() method:
inputEndTime.setText(String.format("%02d:%02d", hourOfDay, minute));
This sets the picked time as text in the EditText field in a format that can then be parsed with format.parse(...) later on.
I think you has to format string before format to Date
Maybe trim().
Date startTimeDate = format.parse(inputTime.getText().toString().trim());
Date endTimeDate = format.parse(inputEndTime.getText().toString().trim());
I have an app that uses alarms to start radio streams. It has a 'repeat daily' function. To check if the alarm should fire on a particular day I check if 'DAY_OF_WEEK' is in an array. Something like this:
int[] repeatOnDays = [0,1,1,1,1,1,1]; // first nr is sunday, last is saturday
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK)-1; // -1 because Sunday==1 but its index in the array is 0
if (repeatOnDays[dayOfWeek]>0) { /* FIRE ALARM TODAY */ }
else { /* DON'T FIRE ALARM TODAY */ }
(Note: above code may not be 100% java, I've simplified stuff)
This morning, when my code ran, it said dayOfWeek was '0' (Sunday) but it's Monday! And when I set another alarm it suddenly said dayOfWeek was '1'.
Wth? How can this happen?
// UPDATE: Here's the actual code:
JSONArray repeatDaily = new JSONArray("[0,1,1,1,1,1,1]"); // <- This is not actually here but it may help read the rest of the code :)
boolean fireToday = true;
if (repeat.equals("daily")) {
Log.d(APPTAG," > Daily repeat..");
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK)-1;
if (repeatDaily.length()<dayOfWeek) { fireToday = false; }
else if (repeatDaily.getInt(dayOfWeek)>0) { fireToday = true; }
else { fireToday = false; }
Log.d(APPTAG," > Day: "+ dayOfWeek +", "+ repeatDaily.getInt(dayOfWeek));
}
if (!fireToday) {
Log.d(APPTAG," > Do not need to fire today");
return; // <-- important stuff
}
Logcat:
06:30:01 D/AlarmMgr > Daily repeat..
06:30:01 D/AlarmMgr > Day: 0, 0
06:30:01 D/AlarmMgr > Do not need to fire today
Looks like it's my own fault. A couple of lines before the code I pasted I set the calendar's time:
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(timeInMs);
But I had some weird code that, in certain conditions, caused timeInMs to be a date in the past.
Changed it to
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(System.currentTimeMillis());
that should fix it :P