diff --git a/app/src/apkFlavor/AndroidManifest.xml b/app/src/apkFlavor/AndroidManifest.xml index cf6a6119..38903380 100644 --- a/app/src/apkFlavor/AndroidManifest.xml +++ b/app/src/apkFlavor/AndroidManifest.xml @@ -144,7 +144,12 @@ - + + + + + + - \ No newline at end of file diff --git a/app/src/main/java/com/jens/automation2/ActivityManageTriggerCalendar.java b/app/src/main/java/com/jens/automation2/ActivityManageTriggerCalendar.java index e171bf35..6bc98c3c 100644 --- a/app/src/main/java/com/jens/automation2/ActivityManageTriggerCalendar.java +++ b/app/src/main/java/com/jens/automation2/ActivityManageTriggerCalendar.java @@ -18,13 +18,14 @@ import androidx.annotation.Nullable; import com.jens.automation2.receivers.CalendarReceiver; -import java.sql.Array; +import org.apache.commons.lang3.StringUtils; + import java.util.ArrayList; import java.util.List; public class ActivityManageTriggerCalendar extends Activity { - CheckBox chkCalendarEventActive, chkCalendarAvailabilityBusy, chkCalendarAvailabilityFree, chkCalendarAvailabilityTentative, chkCalendarAvailabilityOutOfOffice, chkCalendarAvailabilityWorkingElsewhere; + CheckBox chkCalendarEventActive, chkCalendarAvailabilityBusy, chkCalendarAvailabilityFree, chkCalendarAvailabilityTentative, chkCalendarAvailabilityOutOfOffice, chkCalendarAvailabilityWorkingElsewhere, chkCalendarAllDayEvent; Spinner spinnerCalendarTitleDirection, spinnerCalendarLocationDirection, spinnerCalendarDescriptionDirection; EditText etCalendarTitle, etCalendarLocation, etCalendarDescription; LinearLayout llCalendarSelection; @@ -47,6 +48,7 @@ public class ActivityManageTriggerCalendar extends Activity spinnerCalendarTitleDirection = (Spinner)findViewById(R.id.spinnerCalendarTitleDirection); spinnerCalendarLocationDirection = (Spinner)findViewById(R.id.spinnerCalendarLocationDirection); spinnerCalendarDescriptionDirection = (Spinner)findViewById(R.id.spinnerCalendarDescriptionDirection); + chkCalendarAllDayEvent = (CheckBox)findViewById(R.id.chkCalendarAllDayEvent); chkCalendarAvailabilityBusy = (CheckBox)findViewById(R.id.chkCalendarAvailabilityBusy); chkCalendarAvailabilityFree = (CheckBox)findViewById(R.id.chkCalendarAvailabilityFree); chkCalendarAvailabilityTentative = (CheckBox)findViewById(R.id.chkCalendarAvailabilityTentative); @@ -80,7 +82,7 @@ public class ActivityManageTriggerCalendar extends Activity for(CalendarReceiver.AndroidCalendar cal : CalendarReceiver.readCalendars(ActivityManageTriggerCalendar.this)) { CheckBox oneCalCheckbox = new CheckBox(ActivityManageTriggerCalendar.this); - oneCalCheckbox.setText(cal.displayName); + oneCalCheckbox.setText(cal.toString()); oneCalCheckbox.setTag(cal); llCalendarSelection.addView(oneCalCheckbox); checkboxesCalendars.add(oneCalCheckbox); @@ -98,6 +100,18 @@ public class ActivityManageTriggerCalendar extends Activity } }); + chkCalendarAllDayEvent.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() + { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) + { + if(checked) + chkCalendarAllDayEvent.setText(getResources().getString(R.string.allDayEventTrue)); + else + chkCalendarAllDayEvent.setText(getResources().getString(R.string.allDayEventFalse)); + } + }); + bSaveTriggerCalendar.setOnClickListener(new View.OnClickListener() { @Override @@ -140,6 +154,7 @@ public class ActivityManageTriggerCalendar extends Activity titleDir + Trigger.triggerParameter2Split + title + Trigger.triggerParameter2Split + descriptionDir + Trigger.triggerParameter2Split + description + Trigger.triggerParameter2Split + locationDir + Trigger.triggerParameter2Split + location + Trigger.triggerParameter2Split + + String.valueOf(chkCalendarAllDayEvent.isChecked()) + Trigger.triggerParameter2Split + Miscellaneous.explode(separator, availabilityList.toArray(new String[availabilityList.size()])) + Trigger.triggerParameter2Split + Miscellaneous.explode(separator, selectedCalendarsIdArray.toArray(new String[selectedCalendarsIdArray.size()])); @@ -174,8 +189,9 @@ public class ActivityManageTriggerCalendar extends Activity 3 = description 4 = locationDir 5 = location - 6 = availability list - 7 = calendars list + 6 = all day event + 7 = availability list + 8 = calendars list */ for(int i = 0; i < directions.length; i++) @@ -194,52 +210,65 @@ public class ActivityManageTriggerCalendar extends Activity etCalendarDescription.setText(input[3]); etCalendarLocation.setText(input[5]); - String[] availabilities = input[6].split(separator); - String[] calendars = input[7].split(separator); + chkCalendarAllDayEvent.setChecked(Boolean.parseBoolean(input[6])); - for(String avail : availabilities) - { - if(Integer.parseInt(avail) == CalendarContract.Events.AVAILABILITY_BUSY) - chkCalendarAvailabilityBusy.setChecked(true); - else if(Integer.parseInt(avail) == CalendarContract.Events.AVAILABILITY_FREE) - chkCalendarAvailabilityFree.setChecked(true); - else if(Integer.parseInt(avail) == CalendarContract.Events.AVAILABILITY_TENTATIVE) - chkCalendarAvailabilityTentative.setChecked(true); - else if(Integer.parseInt(avail) == CalendarReceiver.AVAILABILITY_OUT_OF_OFFICE) - chkCalendarAvailabilityOutOfOffice.setChecked(true); - else if(Integer.parseInt(avail) == CalendarReceiver.AVAILABILITY_WORKING_ELSEWHERE) - chkCalendarAvailabilityWorkingElsewhere.setChecked(true); - } + String[] availabilities = null; + if(!StringUtils.isEmpty(input[7])) + availabilities = input[7].split(separator); - List usedCalendarIDs = new ArrayList<>(); - List unusedCalendarIDs = new ArrayList<>(); - for(CheckBox checkbox : checkboxesCalendars) + String[] calendars = null; + if(!StringUtils.isEmpty(input[8])) + calendars = input[8].split(separator); + + if(availabilities != null) { - int id = ((CalendarReceiver.AndroidCalendar)checkbox.getTag()).calendarId; - for(String calId : calendars) + for (String avail : availabilities) { - if(calId.equals(String.valueOf(id))) - { - usedCalendarIDs.add(String.valueOf(id)); - checkbox.setChecked(true); - break; - } + if (Integer.parseInt(avail) == CalendarContract.Events.AVAILABILITY_BUSY) + chkCalendarAvailabilityBusy.setChecked(true); + else if (Integer.parseInt(avail) == CalendarContract.Events.AVAILABILITY_FREE) + chkCalendarAvailabilityFree.setChecked(true); + else if (Integer.parseInt(avail) == CalendarContract.Events.AVAILABILITY_TENTATIVE) + chkCalendarAvailabilityTentative.setChecked(true); + else if (Integer.parseInt(avail) == CalendarReceiver.AVAILABILITY_OUT_OF_OFFICE) + chkCalendarAvailabilityOutOfOffice.setChecked(true); + else if (Integer.parseInt(avail) == CalendarReceiver.AVAILABILITY_WORKING_ELSEWHERE) + chkCalendarAvailabilityWorkingElsewhere.setChecked(true); } } - for(String calId : calendars) - { - if(!Miscellaneous.arraySearch((ArrayList) usedCalendarIDs, calId, false, true)) - unusedCalendarIDs.add(calId); - } - if(unusedCalendarIDs.size() > 0) + + if(calendars != null) { + List usedCalendarIDs = new ArrayList<>(); + List unusedCalendarIDs = new ArrayList<>(); + for (CheckBox checkbox : checkboxesCalendars) + { + int id = ((CalendarReceiver.AndroidCalendar) checkbox.getTag()).calendarId; + for (String calId : calendars) + { + if (calId.equals(String.valueOf(id))) + { + usedCalendarIDs.add(String.valueOf(id)); + checkbox.setChecked(true); + break; + } + } + } + for (String calId : calendars) + { + if (!Miscellaneous.arraySearch((ArrayList) usedCalendarIDs, calId, false, true)) + unusedCalendarIDs.add(calId); + } + if (unusedCalendarIDs.size() > 0) + { /* A calendar has been configured that has been deleted since. We cannot resolve it. It will be removed with the next save, but we should inform this user of these circumstances. */ - tvMissingCalendarHint.setText(String.format(getResources().getString(R.string.calendarsMissingHint), Miscellaneous.explode(", ", (ArrayList) unusedCalendarIDs))); + tvMissingCalendarHint.setText(String.format(getResources().getString(R.string.calendarsMissingHint), Miscellaneous.explode(", ", (ArrayList) unusedCalendarIDs))); + } } } } diff --git a/app/src/main/java/com/jens/automation2/Trigger.java b/app/src/main/java/com/jens/automation2/Trigger.java index 4b47da7f..2f12e428 100644 --- a/app/src/main/java/com/jens/automation2/Trigger.java +++ b/app/src/main/java/com/jens/automation2/Trigger.java @@ -631,8 +631,9 @@ public class Trigger 3 = description 4 = eventLocationDirection 5 = eventLocation - 6 = availabilityDirection - 7 = availability + 6 = all day event + 7 = availabilityList + 8 = calendarList */ for(CalendarReceiver.CalendarEvent event : calendarEvents) @@ -641,7 +642,7 @@ public class Trigger if(isActive != event.isCurrentlyActive()) { Miscellaneous.logEvent("i", "CalendarCheck", "Event has to be currently active: " + String.valueOf(triggerParameter) + ", but is required otherwise.", 5); - break; + continue; } if(!StringUtils.isEmpty(conditions[1])) @@ -649,7 +650,7 @@ public class Trigger if (!Miscellaneous.compare(conditions[0], conditions[1], event.title)) { Miscellaneous.logEvent("i", "CalendarCheck", "Title does not match.", 5); - break; + continue; } } @@ -658,7 +659,7 @@ public class Trigger if (!Miscellaneous.compare(conditions[2], conditions[3], event.description)) { Miscellaneous.logEvent("i", "CalendarCheck", "Description does not match.", 5); - break; + continue; } } @@ -667,27 +668,39 @@ public class Trigger if (!Miscellaneous.compare(conditions[4], conditions[5], event.location)) { Miscellaneous.logEvent("i", "CalendarCheck", "Location does not match.", 5); - break; + continue; } } - String[] availabilities = conditions[6].split(ActivityManageTriggerCalendar.separator); - if(availabilities.length > 0) + if (Boolean.parseBoolean(conditions[6]) != event.allDay) { - if(!Miscellaneous.arraySearch(availabilities, event.availability, false, true)) + Miscellaneous.logEvent("i", "CalendarCheck", "All day setting does not match.", 5); + continue; + } + + if(!StringUtils.isEmpty(conditions[7])) + { + String[] availabilities = conditions[7].split(ActivityManageTriggerCalendar.separator); + if (availabilities.length > 0) { - Miscellaneous.logEvent("i", "CalendarCheck", "Availability does not match.", 5); - break; + if (!Miscellaneous.arraySearch(availabilities, event.availability, false, true)) + { + Miscellaneous.logEvent("i", "CalendarCheck", "Availability does not match.", 5); + continue; + } } } - String[] calendars = conditions[7].split(ActivityManageTriggerCalendar.separator); - if(availabilities.length > 0) + if(!StringUtils.isEmpty(conditions[8])) { - if(!Miscellaneous.arraySearch(calendars, String.valueOf(event.calendarId), false, true)) + String[] calendars = conditions[8].split(ActivityManageTriggerCalendar.separator); + if (calendars.length > 0) { - Miscellaneous.logEvent("i", "CalendarCheck", "Calendar does not match.", 5); - break; + if (!Miscellaneous.arraySearch(calendars, String.valueOf(event.calendarId), false, true)) + { + Miscellaneous.logEvent("i", "CalendarCheck", "Calendar does not match.", 5); + continue; + } } } @@ -696,9 +709,16 @@ public class Trigger return true; } - //At this point none of the calendar items matches this trigger + // At this point none of the calendar items matches this trigger - //TODO: If trigger demands no calendar event and there is absolutely no future event, we'll need to check for that. + // If trigger demands no calendar event and there is absolutely no future event, we'll need to check for that. + if(calendarEvents.size() == 0) + { + if(getTriggerParameter() == false) + return true; + + // Further criteria don't matter if there are no events to check + } } catch(Exception e) { @@ -1927,9 +1947,9 @@ public class Trigger || !StringUtils.isEmpty(conditions[5]) || - !StringUtils.isEmpty(conditions[6]) + !StringUtils.isEmpty(conditions[7]) || - !StringUtils.isEmpty(conditions[7])) + !StringUtils.isEmpty(conditions[8])) { returnString.append(" ("); @@ -1940,11 +1960,16 @@ public class Trigger if (!StringUtils.isEmpty(conditions[5])) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.calendarDescription) + " " + conditions[4] + " " + conditions[5] + ", "); - if (!StringUtils.isEmpty(conditions[6])) - returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.availabilities) + " " + conditions[6] + ", "); + if(Boolean.parseBoolean(conditions[6])) + returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.allDayEventTrue) + ", "); + else + returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.allDayEventFalse) + ", "); if (!StringUtils.isEmpty(conditions[7])) - returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.calendars) + " " + conditions[7]); + returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.availabilities) + " " + conditions[7] + ", "); + + if (!StringUtils.isEmpty(conditions[8])) + returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.calendars) + " " + conditions[8]); if (returnString.toString().endsWith(", ")) returnString.delete(returnString.length() - 2, returnString.length()); diff --git a/app/src/main/java/com/jens/automation2/receivers/CalendarReceiver.java b/app/src/main/java/com/jens/automation2/receivers/CalendarReceiver.java index f0e047b6..1ad92d05 100644 --- a/app/src/main/java/com/jens/automation2/receivers/CalendarReceiver.java +++ b/app/src/main/java/com/jens/automation2/receivers/CalendarReceiver.java @@ -30,6 +30,7 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis public static final int AVAILABILITY_WORKING_ELSEWHERE = 5; static List calendarsCache = null; + static List calendarEventsCache = null; public static CalendarReceiver getInstance() { @@ -44,6 +45,9 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis { if(intent.getAction().equalsIgnoreCase(Intent.ACTION_PROVIDER_CHANGED)) { + calendarsCache = null; + calendarEventsCache = null; + ArrayList ruleCandidates = Rule.findRuleCandidates(Trigger.Trigger_Enum.calendarEvent); for(int i = 0; i < ruleCandidates.size(); i++) { @@ -65,6 +69,7 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis { calendarIntentFilter = new IntentFilter(); calendarIntentFilter.addAction(Intent.ACTION_PROVIDER_CHANGED); +// calendarIntentFilter.addDataScheme("content"); } AutomationService.getInstance().registerReceiver(calendarReceiverInstance, calendarIntentFilter); @@ -104,6 +109,14 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis { public int calendarId; public String displayName; + public String accountString; + + @NonNull + @Override + public String toString() + { + return displayName + " (" + accountString + ")"; + } } public static class CalendarEvent @@ -142,7 +155,7 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis cursor = context.getContentResolver().query( Uri.parse("content://com.android.calendar/calendars"), - new String[]{"_id", "calendar_displayName"}, + new String[]{ "_id", "calendar_displayName", "ownerAccount", }, null, null, null); cursor.moveToFirst(); @@ -158,6 +171,7 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis AndroidCalendar calendar = new AndroidCalendar(); calendar.calendarId = Integer.parseInt(cursor.getString(0)); calendar.displayName = cursor.getString(1); + calendar.accountString = cursor.getString(2); calendarsCache.add(calendar); } @@ -176,58 +190,61 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis public static List readCalendarEvents(Context context, boolean includePastEvents) { - Cursor cursor; - - 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); - - cursor.moveToFirst(); - // fetching calendars name - String CNames[] = new String[cursor.getCount()]; - - List eventlist = new ArrayList<>(); - - Calendar now = Calendar.getInstance(); - - for (int i = 0; i < CNames.length; i++) + if(calendarEventsCache == null) { - try + calendarEventsCache = new ArrayList<>(); + + Cursor cursor; + + 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); + + cursor.moveToFirst(); + // fetching calendars name + String CNames[] = new String[cursor.getCount()]; + + Calendar now = Calendar.getInstance(); + + for (int i = 0; i < CNames.length; i++) { - CalendarEvent event = new CalendarEvent(); - event.calendarId = Integer.parseInt(cursor.getString(0)); - - for(AndroidCalendar cal : readCalendars(context)) + try { - if(cal.calendarId == event.calendarId) + CalendarEvent event = new CalendarEvent(); + event.calendarId = Integer.parseInt(cursor.getString(0)); + + for(AndroidCalendar cal : readCalendars(context)) { - event.calendar = cal; - break; + if(cal.calendarId == event.calendarId) + { + event.calendar = cal; + break; + } } + + 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); } - - 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()) - eventlist.add(event); + catch (Exception e) + {} + cursor.moveToNext(); } - catch (Exception e) - {} - cursor.moveToNext(); + + if(cursor != null) + cursor.close(); } - if(cursor != null) - cursor.close(); - - return eventlist; + return calendarEventsCache; } public static void startCalendarReceiver(final AutomationService automationServiceRef) diff --git a/app/src/main/res/layout/activity_manage_trigger_calendar.xml b/app/src/main/res/layout/activity_manage_trigger_calendar.xml index 4890bfd5..4731b46c 100644 --- a/app/src/main/res/layout/activity_manage_trigger_calendar.xml +++ b/app/src/main/res/layout/activity_manage_trigger_calendar.xml @@ -168,6 +168,30 @@ + + + + + + + + + + any calender availabilities In this trigger calendars with IDs %1$s have been previously configured, but have been deleted since. With the next save those will be removed from this trigger. Until then this trigger/condition will never be met. + account + All day event + event is an all day event + event is not an all day event \ No newline at end of file