415 lines
14 KiB
Java
Raw Normal View History

2023-12-23 13:55:02 +01:00
package com.jens.automation2.receivers;
2023-12-30 23:26:27 +01:00
import android.app.AlarmManager;
import android.app.PendingIntent;
2023-12-23 13:55:02 +01:00
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
2023-12-30 23:26:27 +01:00
import android.os.Build;
import android.os.SystemClock;
2023-12-23 13:55:02 +01:00
2023-12-27 14:48:27 +01:00
import androidx.annotation.NonNull;
2023-12-23 13:55:02 +01:00
import com.jens.automation2.AutomationService;
import com.jens.automation2.Miscellaneous;
import com.jens.automation2.Rule;
import com.jens.automation2.Trigger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
2023-12-29 19:43:50 +01:00
import java.util.Timer;
import java.util.TimerTask;
2023-12-23 13:55:02 +01:00
public class CalendarReceiver extends BroadcastReceiver implements AutomationListenerInterface
{
2023-12-25 11:57:55 +01:00
static CalendarReceiver calendarReceiverInstance = null;
2023-12-23 13:55:02 +01:00
static boolean calendarReceiverActive = false;
static IntentFilter calendarIntentFilter = null;
2023-12-25 11:57:55 +01:00
private static AutomationService automationServiceRef;
private static Intent calendarIntent = null;
2023-12-27 13:33:09 +01:00
public static final int AVAILABILITY_OUT_OF_OFFICE = 4;
public static final int AVAILABILITY_WORKING_ELSEWHERE = 5;
2023-12-31 15:54:24 +01:00
public static final String calendarAlarmAction = "ALARM_FOR_CALENDAR";
2023-12-27 13:33:09 +01:00
static List<AndroidCalendar> calendarsCache = null;
2023-12-28 17:17:08 +01:00
static List<CalendarEvent> calendarEventsCache = null;
2023-12-27 13:33:09 +01:00
2023-12-29 19:43:50 +01:00
static Timer timer = null;
static TimerTask timerTask = null;
static Calendar nextWakeup = null;
2023-12-30 23:26:27 +01:00
static AlarmManager alarmManager = null;
static boolean alarmHasChanged = false;
2023-12-29 19:43:50 +01:00
2023-12-25 11:57:55 +01:00
public static CalendarReceiver getInstance()
{
if(calendarReceiverInstance == null)
calendarReceiverInstance = new CalendarReceiver();
return calendarReceiverInstance;
}
2023-12-23 13:55:02 +01:00
@Override
public void onReceive(Context context, Intent intent)
{
if(intent.getAction().equalsIgnoreCase(Intent.ACTION_PROVIDER_CHANGED))
{
2023-12-29 19:43:50 +01:00
Miscellaneous.logEvent("i", "CalendarReceiver", "Received " + intent.getAction(), 5);
2023-12-28 17:17:08 +01:00
calendarsCache = null;
calendarEventsCache = null;
2023-12-29 19:43:50 +01:00
checkForRules(context);
armOrRearmTimer();
}
2023-12-31 15:54:24 +01:00
else if(intent.getAction().equalsIgnoreCase(calendarAlarmAction))
{
Miscellaneous.logEvent("i", "AlarmReceiver", "Received alarm for calendar receiver.", 5);
routineAtAlarm();
}
2023-12-29 19:43:50 +01:00
}
private static void checkForRules(Context context)
{
ArrayList<Rule> ruleCandidates = Rule.findRuleCandidates(Trigger.Trigger_Enum.calendarEvent);
for(int i = 0; i < ruleCandidates.size(); i++)
{
if(ruleCandidates.get(i).getsGreenLight(context))
ruleCandidates.get(i).activate(AutomationService.getInstance(), false);
2023-12-23 13:55:02 +01:00
}
}
@Override
public void startListener(AutomationService automationService)
{
if(!calendarReceiverActive)
{
if(calendarReceiverInstance == null)
2023-12-25 11:57:55 +01:00
calendarReceiverInstance = new CalendarReceiver();
2023-12-23 13:55:02 +01:00
if(calendarIntentFilter == null)
{
calendarIntentFilter = new IntentFilter();
calendarIntentFilter.addAction(Intent.ACTION_PROVIDER_CHANGED);
2023-12-28 17:17:08 +01:00
// calendarIntentFilter.addDataScheme("content");
2023-12-23 13:55:02 +01:00
}
AutomationService.getInstance().registerReceiver(calendarReceiverInstance, calendarIntentFilter);
calendarReceiverActive = true;
}
}
@Override
public void stopListener(AutomationService automationService)
{
if(calendarReceiverActive)
{
if(calendarReceiverInstance != null)
{
AutomationService.getInstance().unregisterReceiver(calendarReceiverInstance);
calendarReceiverInstance = null;
}
calendarReceiverActive = false;
}
}
@Override
public boolean isListenerRunning()
{
return calendarReceiverActive;
}
@Override
public Trigger.Trigger_Enum[] getMonitoredTrigger()
{
return new Trigger.Trigger_Enum[]{Trigger.Trigger_Enum.calendarEvent};
}
2023-12-27 13:33:09 +01:00
public static class AndroidCalendar
{
public int calendarId;
public String displayName;
2023-12-28 17:17:08 +01:00
public String accountString;
@NonNull
@Override
public String toString()
{
return displayName + " (" + accountString + ")";
}
2023-12-27 13:33:09 +01:00
}
2023-12-23 13:55:02 +01:00
public static class CalendarEvent
{
2023-12-27 13:33:09 +01:00
public AndroidCalendar calendar;
public int calendarId;
public String eventId;
public String title;
public String description;
public String location;
public String availability;
2023-12-23 13:55:02 +01:00
public Calendar start, end;
2023-12-25 14:28:48 +01:00
public boolean allDay;
2023-12-23 13:55:02 +01:00
2023-12-27 14:48:27 +01:00
public boolean isCurrentlyActive()
2023-12-23 13:55:02 +01:00
{
Calendar now = Calendar.getInstance();
return now.getTimeInMillis() >= start.getTimeInMillis() && now.getTimeInMillis() < end.getTimeInMillis();
}
2023-12-27 14:48:27 +01:00
@NonNull
@Override
public String toString()
{
return title;
}
2023-12-23 13:55:02 +01:00
}
2023-12-27 13:33:09 +01:00
public static List<AndroidCalendar> readCalendars(Context context)
{
if(calendarsCache == null)
{
calendarsCache = new ArrayList<>();
Cursor cursor;
cursor = context.getContentResolver().query(
Uri.parse("content://com.android.calendar/calendars"),
2023-12-28 17:17:08 +01:00
new String[]{ "_id", "calendar_displayName", "ownerAccount", },
2023-12-27 13:33:09 +01:00
null, null, null);
cursor.moveToFirst();
// fetching calendars name
String CNames[] = new String[cursor.getCount()];
List<AndroidCalendar> calendarlist = new ArrayList<>();
for (int i = 0; i < CNames.length; i++)
{
try
{
AndroidCalendar calendar = new AndroidCalendar();
calendar.calendarId = Integer.parseInt(cursor.getString(0));
calendar.displayName = cursor.getString(1);
2023-12-28 17:17:08 +01:00
calendar.accountString = cursor.getString(2);
2023-12-27 13:33:09 +01:00
calendarsCache.add(calendar);
}
catch (Exception e)
{
}
cursor.moveToNext();
}
if (cursor != null)
cursor.close();
}
return calendarsCache;
}
2023-12-26 11:56:02 +01:00
public static List<CalendarEvent> readCalendarEvents(Context context, boolean includePastEvents)
2023-12-23 13:55:02 +01:00
{
2023-12-28 17:17:08 +01:00
if(calendarEventsCache == null)
{
calendarEventsCache = new ArrayList<>();
2023-12-25 14:28:48 +01:00
2023-12-28 17:17:08 +01:00
Cursor cursor;
2023-12-23 13:55:02 +01:00
2023-12-28 17:17:08 +01:00
cursor = context.getContentResolver().query(
Uri.parse("content://com.android.calendar/events"),
new String[] { "calendar_id", "_id", "title", "description", "allDay", "dtstart", "dtend", "eventLocation", "availability" },
null, null, null);
2023-12-23 13:55:02 +01:00
2023-12-28 17:17:08 +01:00
cursor.moveToFirst();
// fetching calendars name
String CNames[] = new String[cursor.getCount()];
2023-12-23 13:55:02 +01:00
2023-12-28 17:17:08 +01:00
Calendar now = Calendar.getInstance();
2023-12-26 11:56:02 +01:00
2023-12-28 17:17:08 +01:00
for (int i = 0; i < CNames.length; i++)
2023-12-25 11:57:55 +01:00
{
2023-12-28 17:17:08 +01:00
try
2023-12-27 13:33:09 +01:00
{
2023-12-28 17:17:08 +01:00
CalendarEvent event = new CalendarEvent();
event.calendarId = Integer.parseInt(cursor.getString(0));
for(AndroidCalendar cal : readCalendars(context))
2023-12-27 13:33:09 +01:00
{
2023-12-28 17:17:08 +01:00
if(cal.calendarId == event.calendarId)
{
event.calendar = cal;
break;
}
2023-12-27 13:33:09 +01:00
}
2023-12-28 17:17:08 +01:00
event.eventId = cursor.getString(1);
event.title = cursor.getString(2);
event.description = cursor.getString(3);
event.allDay = cursor.getString(4).equals("1");
event.start = Miscellaneous.calendarFromLong(Long.parseLong(cursor.getString(5)));
event.end = Miscellaneous.calendarFromLong(Long.parseLong(cursor.getString(6)));
event.location = cursor.getString(7);
event.availability = cursor.getString(8);
if(includePastEvents || event.end.getTimeInMillis() > now.getTimeInMillis())
calendarEventsCache.add(event);
}
catch (Exception e)
{}
cursor.moveToNext();
2023-12-25 11:57:55 +01:00
}
2023-12-23 13:55:02 +01:00
2023-12-28 17:17:08 +01:00
if(cursor != null)
cursor.close();
2023-12-29 19:43:50 +01:00
2023-12-28 17:17:08 +01:00
}
2023-12-25 14:28:48 +01:00
2023-12-28 17:17:08 +01:00
return calendarEventsCache;
2023-12-23 13:55:02 +01:00
}
2023-12-25 11:57:55 +01:00
2023-12-30 23:26:27 +01:00
protected static void routineAtAlarm()
{
checkForRules(Miscellaneous.getAnyContext());
// Set next timer
calculateNextWakeup();
armOrRearmTimer();
}
2023-12-29 19:43:50 +01:00
private static void armOrRearmTimer()
{
2023-12-30 23:26:27 +01:00
PendingIntent pi = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
2023-12-29 19:43:50 +01:00
{
2023-12-30 23:26:27 +01:00
if (alarmManager == null)
2023-12-29 19:43:50 +01:00
{
2023-12-30 23:26:27 +01:00
alarmManager = (AlarmManager) Miscellaneous.getAnyContext().getSystemService(Context.ALARM_SERVICE);
2023-12-31 16:53:59 +01:00
}
2023-12-29 19:43:50 +01:00
2023-12-31 16:53:59 +01:00
if(pi == null)
{
2023-12-31 15:54:24 +01:00
Intent intent = new Intent(Miscellaneous.getAnyContext(), CalendarReceiver.class);
intent.setAction(calendarAlarmAction);
pi = PendingIntent.getBroadcast(AutomationService.getInstance(), 0, intent, 0);
2023-12-29 19:43:50 +01:00
}
2023-12-30 23:26:27 +01:00
}
else
2023-12-29 19:43:50 +01:00
{
2023-12-30 23:26:27 +01:00
timerTask = new TimerTask()
{
@Override
public void run()
{
routineAtAlarm();
}
};
if(timer != null)
{
timer.cancel();
timer.purge();
}
timer = new Timer();
2023-12-29 19:43:50 +01:00
}
if(nextWakeup == null)
{
readCalendarEvents(Miscellaneous.getAnyContext(), false);
calculateNextWakeup();
}
// If it's now filled, go on
if(nextWakeup != null)
2023-12-30 23:26:27 +01:00
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && alarmManager.canScheduleExactAlarms()))
{
try
{
alarmManager.cancel(pi);
}
catch (Exception e)
{
}
Miscellaneous.logEvent("i", "armOrRearmTimer()", "Setting calendar alarm for " + nextWakeup.toString(), 5);
2023-12-31 15:54:24 +01:00
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nextWakeup.getTimeInMillis(), pi);
//alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextWakeup.getTimeInMillis(), pi);
2023-12-30 23:26:27 +01:00
}
}
else
timer.schedule(timerTask, nextWakeup.getTimeInMillis());
}
2023-12-29 19:43:50 +01:00
}
private static void calculateNextWakeup()
{
Calendar now = Calendar.getInstance();
if (nextWakeup != null && nextWakeup.getTimeInMillis() < now.getTimeInMillis())
nextWakeup = null;
List<CalendarEvent> events = readCalendarEvents(Miscellaneous.getAnyContext(), false);
if (events.size() > 0)
{
for (CalendarEvent event : events)
{
if (event.isCurrentlyActive())
{
if (nextWakeup == null || event.end.getTimeInMillis() < nextWakeup.getTimeInMillis())
{
nextWakeup = event.end;
2023-12-31 16:53:59 +01:00
Miscellaneous.logEvent("i", "calculateNextWakeupForCalendar()", "Chose end of event " + event.title + " as next wakeup.", 5);
2023-12-30 23:26:27 +01:00
if(!alarmHasChanged)
alarmHasChanged = true;
2023-12-29 19:43:50 +01:00
}
}
else
{
if (nextWakeup == null || event.start.getTimeInMillis() < nextWakeup.getTimeInMillis())
{
nextWakeup = event.start;
2023-12-31 16:53:59 +01:00
Miscellaneous.logEvent("i", "calculateNextWakeupForCalendar()", "Chose start of event " + event.title + " as next wakeup.", 5);
2023-12-30 23:26:27 +01:00
if(!alarmHasChanged)
alarmHasChanged = true;
2023-12-29 19:43:50 +01:00
}
}
}
}
//else
// we expect to be called byOnReceive() when new items exist
}
2023-12-25 11:57:55 +01:00
public static void startCalendarReceiver(final AutomationService automationServiceRef)
{
if (!calendarReceiverActive)
{
CalendarReceiver.automationServiceRef = automationServiceRef;
if (calendarReceiverInstance == null)
calendarReceiverInstance = new CalendarReceiver();
if (calendarIntentFilter == null)
{
calendarIntentFilter = new IntentFilter();
calendarIntentFilter.addAction(Intent.ACTION_PROVIDER_CHANGED);
2023-12-29 19:43:50 +01:00
calendarIntentFilter.addDataScheme("content");
calendarIntentFilter.addDataAuthority("com.android.calendar", null);
2023-12-25 11:57:55 +01:00
}
calendarIntent = automationServiceRef.registerReceiver(calendarReceiverInstance, calendarIntentFilter);
calendarReceiverActive = true;
2023-12-29 19:43:50 +01:00
armOrRearmTimer();
2023-12-25 11:57:55 +01:00
}
}
2023-12-23 13:55:02 +01:00
}