diff --git a/app/src/apkFlavor/AndroidManifest.xml b/app/src/apkFlavor/AndroidManifest.xml index 3890338..cf6a611 100644 --- a/app/src/apkFlavor/AndroidManifest.xml +++ b/app/src/apkFlavor/AndroidManifest.xml @@ -144,12 +144,7 @@ - - - - - - + directionSpinnerAdapter; + public static int requestCodePermissionReadCalendar = 815; @Override protected void onCreate(@Nullable Bundle savedInstanceState) @@ -79,14 +86,36 @@ public class ActivityManageTriggerCalendar extends Activity spinnerCalendarDescriptionDirection.setAdapter(directionSpinnerAdapter); directionSpinnerAdapter.notifyDataSetChanged(); - for(CalendarReceiver.AndroidCalendar cal : CalendarReceiver.readCalendars(ActivityManageTriggerCalendar.this)) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - CheckBox oneCalCheckbox = new CheckBox(ActivityManageTriggerCalendar.this); - oneCalCheckbox.setText(cal.toString()); - oneCalCheckbox.setTag(cal); - llCalendarSelection.addView(oneCalCheckbox); - checkboxesCalendars.add(oneCalCheckbox); + if(ActivityPermissions.havePermission(Manifest.permission.READ_CALENDAR, ActivityManageTriggerCalendar.this) || ActivityPermissions.havePermission(Manifest.permission.WRITE_CALENDAR, ActivityManageTriggerCalendar.this)) + populateCalenderCheckboxes(); + else + { + AlertDialog.Builder builder = new AlertDialog.Builder(ActivityManageTriggerCalendar.this); + builder.setTitle(getResources().getString(R.string.info)); + builder.setMessage(getResources().getString(R.string.permissionCalendarRequired)); + builder.setNegativeButton(getResources().getString(R.string.cancel), new DialogInterface.OnClickListener() + { + @Override + public void onClick(DialogInterface dialogInterface, int i) + { + ActivityManageTriggerCalendar.this.finish(); + } + }); + builder.setPositiveButton(getResources().getString(R.string.ok), new DialogInterface.OnClickListener() + { + @Override + public void onClick(DialogInterface dialogInterface, int i) + { + requestPermissions(new String[]{ Manifest.permission.READ_CALENDAR } , requestCodePermissionReadCalendar); + } + }); + builder.show(); + } } + else + populateCalenderCheckboxes(); chkCalendarEventActive.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @@ -172,6 +201,30 @@ public class ActivityManageTriggerCalendar extends Activity loadValuesIntoGui(inputIntent); } + private void populateCalenderCheckboxes() + { + List calList = CalendarReceiver.readCalendars(ActivityManageTriggerCalendar.this); + + if(calList != null) + { + if(calList.size() > 0) + { + for (CalendarReceiver.AndroidCalendar cal : calList) + { + CheckBox oneCalCheckbox = new CheckBox(ActivityManageTriggerCalendar.this); + oneCalCheckbox.setText(cal.toString()); + oneCalCheckbox.setTag(cal); + llCalendarSelection.addView(oneCalCheckbox); + checkboxesCalendars.add(oneCalCheckbox); + } + } + else + Miscellaneous.messageBox(getResources().getString(R.string.warning), getResources().getString(R.string.noCalendarsOnYourDevice), ActivityManageTriggerCalendar.this).show(); + } + else + Miscellaneous.messageBox(getResources().getString(R.string.warning), getResources().getString(R.string.errorReadingCalendars), ActivityManageTriggerCalendar.this).show(); + } + void loadValuesIntoGui(Intent data) { //TODO:try-catch @@ -181,7 +234,7 @@ public class ActivityManageTriggerCalendar extends Activity if(data.hasExtra(ActivityManageRule.intentNameTriggerParameter2)) { - String input[] = data.getStringExtra(ActivityManageRule.intentNameTriggerParameter2).split(Trigger.triggerParameter2Split); + String input[] = data.getStringExtra(ActivityManageRule.intentNameTriggerParameter2).split(Trigger.triggerParameter2Split, -1); /* 0 = titleDir 1 = title @@ -216,10 +269,6 @@ public class ActivityManageTriggerCalendar extends Activity if(!StringUtils.isEmpty(input[7])) availabilities = input[7].split(separator); - String[] calendars = null; - if(!StringUtils.isEmpty(input[8])) - calendars = input[8].split(separator); - if(availabilities != null) { for (String avail : availabilities) @@ -237,6 +286,10 @@ public class ActivityManageTriggerCalendar extends Activity } } + String[] calendars = null; + if(!StringUtils.isEmpty(input[8])) + calendars = input[8].split(separator); + if(calendars != null) { List usedCalendarIDs = new ArrayList<>(); @@ -272,4 +325,25 @@ public class ActivityManageTriggerCalendar extends Activity } } } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) + { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + + if(requestCode == requestCodePermissionReadCalendar) + { + if( + permissions[0].equals(Manifest.permission.READ_CALENDAR) + || + permissions[0].equals(Manifest.permission.WRITE_CALENDAR) + ) + { + if(grantResults[0] == PackageManager.PERMISSION_GRANTED) + populateCalenderCheckboxes(); + else + finish(); + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/jens/automation2/Miscellaneous.java b/app/src/main/java/com/jens/automation2/Miscellaneous.java index 4da9c91..cc035db 100644 --- a/app/src/main/java/com/jens/automation2/Miscellaneous.java +++ b/app/src/main/java/com/jens/automation2/Miscellaneous.java @@ -806,7 +806,7 @@ public class Miscellaneous extends Service alertDialog.setTitle(title); alertDialog.setMessage(message); - alertDialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() + alertDialog.setPositiveButton(context.getResources().getString(R.string.ok), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { diff --git a/app/src/main/java/com/jens/automation2/Trigger.java b/app/src/main/java/com/jens/automation2/Trigger.java index 2f12e42..1db9c20 100644 --- a/app/src/main/java/com/jens/automation2/Trigger.java +++ b/app/src/main/java/com/jens/automation2/Trigger.java @@ -1933,49 +1933,42 @@ public class Trigger returnString.append(String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.variableCheckStringDeleted), triggerParameter2)); break; case calendarEvent: + returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.calendarEvent)); + + returnString.append(" ("); + if(triggerParameter) returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.eventIsCurrentlyHappening)); else returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.eventIsCurrentlyNotHappening)); + returnString.append( ", "); + String[] conditions = triggerParameter2.split(triggerParameter2Split, -1); - if( - !StringUtils.isEmpty(conditions[1]) - || - !StringUtils.isEmpty(conditions[3]) - || - !StringUtils.isEmpty(conditions[5]) - || - !StringUtils.isEmpty(conditions[7]) - || - !StringUtils.isEmpty(conditions[8])) - { - returnString.append(" ("); + if (!StringUtils.isEmpty(conditions[1])) + returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.title) + " " + conditions[0] + " " + conditions[1] + ", "); + if (!StringUtils.isEmpty(conditions[3])) + returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.location) + " " + conditions[2] + " " + conditions[3] + ", "); + if (!StringUtils.isEmpty(conditions[5])) + returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.calendarDescription) + " " + conditions[4] + " " + conditions[5] + ", "); - if (!StringUtils.isEmpty(conditions[1])) - returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.title) + " " + conditions[0] + " " + conditions[1] + ", "); - if (!StringUtils.isEmpty(conditions[3])) - returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.location) + " " + conditions[2] + " " + conditions[3] + ", "); - if (!StringUtils.isEmpty(conditions[5])) - returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.calendarDescription) + " " + conditions[4] + " " + conditions[5] + ", "); + 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(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.availabilities) + " " + conditions[7] + ", "); - if (!StringUtils.isEmpty(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 (!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()); - if (returnString.toString().endsWith(", ")) - returnString.delete(returnString.length() - 2, returnString.length()); + returnString.append(")"); - returnString.append(")"); - } break; default: returnString.append("error"); 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 1ad92d0..28244ca 100644 --- a/app/src/main/java/com/jens/automation2/receivers/CalendarReceiver.java +++ b/app/src/main/java/com/jens/automation2/receivers/CalendarReceiver.java @@ -17,6 +17,8 @@ import com.jens.automation2.Trigger; import java.util.ArrayList; import java.util.Calendar; import java.util.List; +import java.util.Timer; +import java.util.TimerTask; public class CalendarReceiver extends BroadcastReceiver implements AutomationListenerInterface { @@ -32,6 +34,10 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis static List calendarsCache = null; static List calendarEventsCache = null; + static Timer timer = null; + static TimerTask timerTask = null; + static Calendar nextWakeup = null; + public static CalendarReceiver getInstance() { if(calendarReceiverInstance == null) @@ -45,15 +51,23 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis { if(intent.getAction().equalsIgnoreCase(Intent.ACTION_PROVIDER_CHANGED)) { + Miscellaneous.logEvent("i", "CalendarReceiver", "Received " + intent.getAction(), 5); + calendarsCache = null; calendarEventsCache = null; - ArrayList 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); - } + checkForRules(context); + armOrRearmTimer(); + } + } + + private static void checkForRules(Context context) + { + ArrayList 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); } } @@ -242,11 +256,79 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis if(cursor != null) cursor.close(); + } return calendarEventsCache; } + private static void armOrRearmTimer() + { + timerTask = new TimerTask() + { + @Override + public void run() + { + checkForRules(Miscellaneous.getAnyContext()); + + // Set next timer + + calculateNextWakeup(); + armOrRearmTimer(); + } + }; + + if(timer != null) + { + timer.cancel(); + timer.purge(); + } + timer = new Timer(); + + if(nextWakeup == null) + { + readCalendarEvents(Miscellaneous.getAnyContext(), false); + calculateNextWakeup(); + } + + // If it's now filled, go on + if(nextWakeup != null) + timer.schedule(timerTask, nextWakeup.getTimeInMillis()); + } + + private static void calculateNextWakeup() + { + Calendar now = Calendar.getInstance(); + if (nextWakeup != null && nextWakeup.getTimeInMillis() < now.getTimeInMillis()) + nextWakeup = null; + + List 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; + Miscellaneous.logEvent("i", "calculateNextWakeupForCalendar()", "Choosing end of event " + event.title + " as next wakeup.", 5); + } + } + else + { + if (nextWakeup == null || event.start.getTimeInMillis() < nextWakeup.getTimeInMillis()) + { + nextWakeup = event.start; + Miscellaneous.logEvent("i", "calculateNextWakeupForCalendar()", "Choosing start of event " + event.title + " as next wakeup.", 5); + } + } + } + } + //else + // we expect to be called byOnReceive() when new items exist + } + public static void startCalendarReceiver(final AutomationService automationServiceRef) { if (!calendarReceiverActive) @@ -260,25 +342,15 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis { calendarIntentFilter = new IntentFilter(); calendarIntentFilter.addAction(Intent.ACTION_PROVIDER_CHANGED); + calendarIntentFilter.addDataScheme("content"); + calendarIntentFilter.addDataAuthority("com.android.calendar", null); } calendarIntent = automationServiceRef.registerReceiver(calendarReceiverInstance, calendarIntentFilter); calendarReceiverActive = true; - } - } - public static void stopScreenStateReceiver() - { - if (calendarReceiverActive) - { - if (calendarReceiverInstance != null) - { - automationServiceRef.unregisterReceiver(calendarReceiverInstance); - calendarReceiverInstance = null; - } - - calendarReceiverActive = false; + armOrRearmTimer(); } } } \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/ear.png b/app/src/main/res/drawable-hdpi/ear.png index 916b101..36cd243 100644 Binary files a/app/src/main/res/drawable-hdpi/ear.png and b/app/src/main/res/drawable-hdpi/ear.png differ 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 4731b46..dac9a54 100644 --- a/app/src/main/res/layout/activity_manage_trigger_calendar.xml +++ b/app/src/main/res/layout/activity_manage_trigger_calendar.xml @@ -301,8 +301,9 @@ diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index bfa12ed..ca3363a 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -765,7 +765,7 @@ Llamar al número de teléfono Llamar al número de teléfono Aquí puede ingresar un número de teléfono al que se llamará sin más indicaciones. Puede usar esto para realizar configuraciones como realizar ajustes en el enrutamiento de llamadas, etc. Por favor, busque los códigos necesarios para esto por su cuenta. - Terminar llamda de teléfono + Terminar llamada de teléfono Terminar llamda de teléfono La configuración y/o las reglas hacen referencia a funciones que no se pueden proporcionar en la versión de Google Play. Entre otras cosas que incluye todo lo relacionado con llamadas telefónicas y mensajes de texto. Si la variable %1$s no está establecida diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4d3ca63..b67e2d7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -918,9 +918,9 @@ tentative out of office working elsewhere - Select no item if any will do. + If you select no item, any one will be ok. Calendars - It may be that only the first 3 types are actually working becaue the other types are not part of Google Calendar. + It may be that only the first 3 types are actually working because the other types are not part of Google Calendar. 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. @@ -928,4 +928,7 @@ All day event event is an all day event event is not an all day event + The permission to read your calendar will be required for a calendar trigger. It will already be required to populate the calendar fields in this window. + It appears like no calendars have been set up on your device. You can save this trigger, but it will never return true. + There was an error reading the calendars on your device. \ No newline at end of file