From 81a205a8db1a6789befea72a32a9c1d2fc9bafa4 Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 30 Dec 2023 23:26:27 +0100 Subject: [PATCH] Calendar trigger --- app/src/apkFlavor/AndroidManifest.xml | 3 + app/src/fdroidFlavor/AndroidManifest.xml | 3 + app/src/googlePlayFlavor/AndroidManifest.xml | 3 + .../jens/automation2/ActivityPermissions.java | 39 ++++++++ .../receivers/CalendarReceiver.java | 89 +++++++++++++++---- app/src/main/res/values/strings.xml | 2 + 6 files changed, 123 insertions(+), 16 deletions(-) diff --git a/app/src/apkFlavor/AndroidManifest.xml b/app/src/apkFlavor/AndroidManifest.xml index cf6a611..84b71d8 100644 --- a/app/src/apkFlavor/AndroidManifest.xml +++ b/app/src/apkFlavor/AndroidManifest.xml @@ -75,6 +75,9 @@ + + + + + + = 31 && Miscellaneous.getTargetSDK(Miscellaneous.getAnyContext()) >= 31) + addToArrayListUnique(Manifest.permission.SCHEDULE_EXACT_ALARM, requiredPermissions); break; case usb_host_connection: addToArrayListUnique(Manifest.permission.READ_PHONE_STATE, requiredPermissions); @@ -582,6 +585,8 @@ public class ActivityPermissions extends Activity break; case calendarEvent: addToArrayListUnique(Manifest.permission.READ_CALENDAR, requiredPermissions); + if(Build.VERSION.SDK_INT >= 31 && Miscellaneous.getTargetSDK(Miscellaneous.getAnyContext()) >= 31) + addToArrayListUnique(Manifest.permission.SCHEDULE_EXACT_ALARM, requiredPermissions); break; default: break; @@ -831,6 +836,12 @@ public class ActivityPermissions extends Activity case Manifest.permission.WRITE_EXTERNAL_STORAGE: usingElements.add(getResources().getString(R.string.storeSettings)); break; + case Manifest.permission.SCHEDULE_EXACT_ALARM: + for(String ruleName : getRulesUsing(Trigger.Trigger_Enum.timeFrame)) + usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName)); + for(String ruleName : getRulesUsing(Trigger.Trigger_Enum.calendarEvent)) + usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName)); + break; case Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE: for(String ruleName : getRulesUsing(Trigger.Trigger_Enum.notification)) usingElements.add(String.format(getResources().getString(R.string.ruleXrequiresThis), ruleName)); @@ -1098,6 +1109,10 @@ public class ActivityPermissions extends Activity if (requestCode == requestCodeForPermissionsAccessibility) if(havePermission(Manifest.permission.BIND_ACCESSIBILITY_SERVICE, ActivityPermissions.this)) requestPermissions(cachedPermissionsToRequest, true); + + if (requestCode == requestCodeForPermissionsScheduleExactAlarms) + if(havePermission(Manifest.permission.SCHEDULE_EXACT_ALARM, ActivityPermissions.this)) + requestPermissions(cachedPermissionsToRequest, true); } } @@ -1225,6 +1240,22 @@ public class ActivityPermissions extends Activity return; } + else if (s.equalsIgnoreCase(Manifest.permission.SCHEDULE_EXACT_ALARM)) + { + AlertDialog diag = Miscellaneous.messageBox(getResources().getString(R.string.info), getResources().getString(R.string.alarmsPermissionHint), ActivityPermissions.this); + diag.setOnDismissListener(new DialogInterface.OnDismissListener() + { + @Override + public void onDismiss(DialogInterface dialogInterface) + { + requiredPermissions.remove(s); + cachedPermissionsToRequest = requiredPermissions; + requestScheduleExactAlarms(); + } + }); + diag.show(); + return; + } else if(s.equals(Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)) { requiredPermissions.remove(s); @@ -1310,6 +1341,14 @@ public class ActivityPermissions extends Activity startActivityForResult(intent, requestCodeForPermissionsNotifications); } + + void requestScheduleExactAlarms() + { + Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM); + startActivityForResult(intent, requestCodeForPermissionsScheduleExactAlarms); + } + + protected void applyChanges() { AutomationService service = AutomationService.getInstance(); 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 28244ca..5e25823 100644 --- a/app/src/main/java/com/jens/automation2/receivers/CalendarReceiver.java +++ b/app/src/main/java/com/jens/automation2/receivers/CalendarReceiver.java @@ -1,11 +1,15 @@ package com.jens.automation2.receivers; +import android.app.AlarmManager; +import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.Cursor; import android.net.Uri; +import android.os.Build; +import android.os.SystemClock; import androidx.annotation.NonNull; @@ -37,6 +41,8 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis static Timer timer = null; static TimerTask timerTask = null; static Calendar nextWakeup = null; + static AlarmManager alarmManager = null; + static boolean alarmHasChanged = false; public static CalendarReceiver getInstance() { @@ -262,28 +268,56 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis return calendarEventsCache; } + public static class AlarmReceiver extends BroadcastReceiver + { + @Override + public void onReceive(Context context, Intent intent) + { + Miscellaneous.logEvent("i", "AlarmReceiver", "Received alarm for calendar receiver.", 5); + routineAtAlarm(); + } + } + + protected static void routineAtAlarm() + { + checkForRules(Miscellaneous.getAnyContext()); + + // Set next timer + calculateNextWakeup(); + armOrRearmTimer(); + } + private static void armOrRearmTimer() { - timerTask = new TimerTask() + PendingIntent pi = null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - @Override - public void run() + if (alarmManager == null) { - checkForRules(Miscellaneous.getAnyContext()); + alarmManager = (AlarmManager) Miscellaneous.getAnyContext().getSystemService(Context.ALARM_SERVICE); - // Set next timer - - calculateNextWakeup(); - armOrRearmTimer(); + Intent i = new Intent(Miscellaneous.getAnyContext(), AlarmReceiver.class); + pi = PendingIntent.getBroadcast(Miscellaneous.getAnyContext(), 0, i, 0); } - }; - - if(timer != null) - { - timer.cancel(); - timer.purge(); } - timer = new Timer(); + else + { + timerTask = new TimerTask() + { + @Override + public void run() + { + routineAtAlarm(); + } + }; + + if(timer != null) + { + timer.cancel(); + timer.purge(); + } + timer = new Timer(); + } if(nextWakeup == null) { @@ -293,7 +327,26 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis // If it's now filled, go on if(nextWakeup != null) - timer.schedule(timerTask, nextWakeup.getTimeInMillis()); + { + 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); + alarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextWakeup.getTimeInMillis(), pi); + } + } + else + timer.schedule(timerTask, nextWakeup.getTimeInMillis()); + } } private static void calculateNextWakeup() @@ -313,6 +366,8 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis { nextWakeup = event.end; Miscellaneous.logEvent("i", "calculateNextWakeupForCalendar()", "Choosing end of event " + event.title + " as next wakeup.", 5); + if(!alarmHasChanged) + alarmHasChanged = true; } } else @@ -321,6 +376,8 @@ public class CalendarReceiver extends BroadcastReceiver implements AutomationLis { nextWakeup = event.start; Miscellaneous.logEvent("i", "calculateNextWakeupForCalendar()", "Choosing start of event " + event.title + " as next wakeup.", 5); + if(!alarmHasChanged) + alarmHasChanged = true; } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b67e2d7..45a91c9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -931,4 +931,6 @@ 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. + Schedule exact alarms + After clicking OK a window will open. Please select Automation there and allow the app to schedule exact alarms. \ No newline at end of file