From f457849a78a7215ab59d7e5a55e69e757806e137 Mon Sep 17 00:00:00 2001 From: M66B Date: Sat, 23 Apr 2022 12:44:25 +0200 Subject: [PATCH] Added account ignore schedule --- CHANGELOG.md | 6 ++ FAQ.md | 2 + app/src/main/assets/CHANGELOG.md | 6 ++ .../eu/faircode/email/FragmentAccount.java | 26 ++++-- .../java/eu/faircode/email/FragmentPop.java | 27 ++++-- .../eu/faircode/email/ServiceSynchronize.java | 83 +++++++++++++------ .../email/TupleAccountNetworkState.java | 4 + app/src/main/res/layout/fragment_account.xml | 13 ++- app/src/main/res/layout/fragment_pop.xml | 11 ++- app/src/main/res/values/strings.xml | 1 + metadata/en-US/changelogs/1879.txt | 6 ++ 11 files changed, 141 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b63a81fb9..117d25c9a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ ### [Hulsanpes](https://en.wikipedia.org/wiki/Hulsanpes) +### Next version + +* Added advanced account option to sync outside schedule +* Small improvements and minor bug fixes +* Updated translations + ### 1.1879 - 2022-04-23 * Added warning about airplane mode enabled diff --git a/FAQ.md b/FAQ.md index fea28110c8..da3474ce0c 100644 --- a/FAQ.md +++ b/FAQ.md @@ -2636,6 +2636,8 @@ so there is little room for performance improvements. In the receive settings you can enable scheduling and set a time period and the days of the week *when* messages should be *received*. Note that an end time equal to or earlier than the start time is considered to be 24 hours later. +Since version 1.1880 is is possible to exclude accounts from scheduling in the advanced account settings. + Automation, see below, can be used for more advanced schedules, like for example multiple synchronization periods per day or different synchronization periods for different days. diff --git a/app/src/main/assets/CHANGELOG.md b/app/src/main/assets/CHANGELOG.md index 7b63a81fb9..117d25c9a4 100644 --- a/app/src/main/assets/CHANGELOG.md +++ b/app/src/main/assets/CHANGELOG.md @@ -4,6 +4,12 @@ ### [Hulsanpes](https://en.wikipedia.org/wiki/Hulsanpes) +### Next version + +* Added advanced account option to sync outside schedule +* Small improvements and minor bug fixes +* Updated translations + ### 1.1879 - 2022-04-23 * Added warning about airplane mode enabled diff --git a/app/src/main/java/eu/faircode/email/FragmentAccount.java b/app/src/main/java/eu/faircode/email/FragmentAccount.java index ca12719d39..8872fec8f3 100644 --- a/app/src/main/java/eu/faircode/email/FragmentAccount.java +++ b/app/src/main/java/eu/faircode/email/FragmentAccount.java @@ -112,6 +112,7 @@ public class FragmentAccount extends FragmentBase { private Button btnAdvanced; private CheckBox cbSynchronize; + private CheckBox cbIgnoreSchedule; private CheckBox cbOnDemand; private TextView tvLeave; private CheckBox cbPrimary; @@ -220,6 +221,7 @@ public class FragmentAccount extends FragmentBase { btnAdvanced = view.findViewById(R.id.btnAdvanced); cbSynchronize = view.findViewById(R.id.cbSynchronize); + cbIgnoreSchedule = view.findViewById(R.id.cbIgnoreSchedule); cbOnDemand = view.findViewById(R.id.cbOnDemand); tvLeave = view.findViewById(R.id.tvLeave); cbPrimary = view.findViewById(R.id.cbPrimary); @@ -441,6 +443,7 @@ public class FragmentAccount extends FragmentBase { cbSynchronize.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + cbIgnoreSchedule.setEnabled(checked); cbOnDemand.setEnabled(checked); cbPrimary.setEnabled(checked); } @@ -878,6 +881,7 @@ public class FragmentAccount extends FragmentBase { args.putInt("color", btnColor.getColor()); args.putBoolean("synchronize", cbSynchronize.isChecked()); + args.putBoolean("ignore_schedule", cbIgnoreSchedule.isChecked()); args.putBoolean("ondemand", cbOnDemand.isChecked()); args.putBoolean("primary", cbPrimary.isChecked()); args.putBoolean("notify", cbNotify.isChecked()); @@ -948,6 +952,7 @@ public class FragmentAccount extends FragmentBase { Integer color = args.getInt("color"); boolean synchronize = args.getBoolean("synchronize"); + boolean ignore_schedule = args.getBoolean("ignore_schedule"); boolean ondemand = args.getBoolean("ondemand"); boolean primary = args.getBoolean("primary"); boolean notify = args.getBoolean("notify"); @@ -1043,6 +1048,8 @@ public class FragmentAccount extends FragmentBase { return true; if (!Objects.equals(account.synchronize, synchronize)) return true; + if (ignore_schedule != jconditions.optBoolean("ignore_schedule")) + return true; if (!Objects.equals(account.ondemand, ondemand)) return true; if (!Objects.equals(account.primary, account.synchronize && primary)) @@ -1185,6 +1192,7 @@ public class FragmentAccount extends FragmentBase { account.color = color; account.synchronize = synchronize; + jconditions.put("ignore_schedule", ignore_schedule); account.ondemand = ondemand; account.primary = (account.synchronize && primary); account.notify = notify; @@ -1486,6 +1494,14 @@ public class FragmentAccount extends FragmentBase { spProvider.setAdapter(aaProvider); if (savedInstanceState == null) { + JSONObject jcondition = new JSONObject(); + try { + if (account != null && account.conditions != null) + jcondition = new JSONObject(account.conditions); + } catch (Throwable ex) { + Log.e(ex); + } + if (account != null) { boolean found = false; for (int pos = 2; pos < providers.size(); pos++) { @@ -1544,6 +1560,7 @@ public class FragmentAccount extends FragmentBase { cbNotify.setEnabled(pro); cbSynchronize.setChecked(account == null ? true : account.synchronize); + cbIgnoreSchedule.setChecked(jcondition.optBoolean("ignore_schedule")); cbOnDemand.setChecked(account == null ? false : account.ondemand); cbPrimary.setChecked(account == null ? false : account.primary); cbBrowse.setChecked(account == null ? true : account.browse); @@ -1551,14 +1568,6 @@ public class FragmentAccount extends FragmentBase { etInterval.setText(account == null ? "" : Long.toString(account.poll_interval)); cbPartialFetch.setChecked(account == null ? true : account.partial_fetch); cbIgnoreSize.setChecked(account == null ? false : account.ignore_size); - - JSONObject jcondition = new JSONObject(); - try { - if (account != null && account.conditions != null) - jcondition = new JSONObject(account.conditions); - } catch (Throwable ex) { - Log.e(ex); - } cbUnmetered.setChecked(jcondition.optBoolean("unmetered")); if (account != null && account.use_date) @@ -1686,6 +1695,7 @@ public class FragmentAccount extends FragmentBase { }); } + cbIgnoreSchedule.setEnabled(cbSynchronize.isChecked()); cbOnDemand.setEnabled(cbSynchronize.isChecked()); cbPrimary.setEnabled(cbSynchronize.isChecked()); diff --git a/app/src/main/java/eu/faircode/email/FragmentPop.java b/app/src/main/java/eu/faircode/email/FragmentPop.java index a0867da2ad..e4ae60f697 100644 --- a/app/src/main/java/eu/faircode/email/FragmentPop.java +++ b/app/src/main/java/eu/faircode/email/FragmentPop.java @@ -86,6 +86,7 @@ public class FragmentPop extends FragmentBase { private TextView tvColorPro; private CheckBox cbSynchronize; + private CheckBox cbIgnoreSchedule; private CheckBox cbOnDemand; private CheckBox cbPrimary; private CheckBox cbNotify; @@ -152,6 +153,7 @@ public class FragmentPop extends FragmentBase { tvColorPro = view.findViewById(R.id.tvColorPro); cbSynchronize = view.findViewById(R.id.cbSynchronize); + cbIgnoreSchedule = view.findViewById(R.id.cbIgnoreSchedule); cbOnDemand = view.findViewById(R.id.cbOnDemand); cbPrimary = view.findViewById(R.id.cbPrimary); cbNotify = view.findViewById(R.id.cbNotify); @@ -245,6 +247,7 @@ public class FragmentPop extends FragmentBase { cbSynchronize.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + cbIgnoreSchedule.setEnabled(checked); cbOnDemand.setEnabled(checked); cbPrimary.setEnabled(checked); } @@ -320,6 +323,7 @@ public class FragmentPop extends FragmentBase { args.putInt("color", btnColor.getColor()); args.putBoolean("synchronize", cbSynchronize.isChecked()); + args.putBoolean("ignore_schedule", cbIgnoreSchedule.isChecked()); args.putBoolean("ondemand", cbOnDemand.isChecked()); args.putBoolean("primary", cbPrimary.isChecked()); args.putBoolean("notify", cbNotify.isChecked()); @@ -372,6 +376,7 @@ public class FragmentPop extends FragmentBase { Integer color = args.getInt("color"); boolean synchronize = args.getBoolean("synchronize"); + boolean ignore_schedule = args.getBoolean("ignore_schedule"); boolean ondemand = args.getBoolean("ondemand"); boolean primary = args.getBoolean("primary"); boolean notify = args.getBoolean("notify"); @@ -452,6 +457,8 @@ public class FragmentPop extends FragmentBase { return true; if (!Objects.equals(account.synchronize, synchronize)) return true; + if (ignore_schedule != jconditions.optBoolean("ignore_schedule")) + return true; if (!Objects.equals(account.ondemand, ondemand)) return true; if (!Objects.equals(account.primary, account.synchronize && primary)) @@ -539,6 +546,7 @@ public class FragmentPop extends FragmentBase { account.color = color; account.synchronize = synchronize; + jconditions.put("ignore_schedule", ignore_schedule); account.ondemand = ondemand; account.primary = (account.synchronize && primary); account.notify = notify; @@ -695,6 +703,14 @@ public class FragmentPop extends FragmentBase { @Override protected void onExecuted(Bundle args, final EntityAccount account) { if (savedInstanceState == null) { + JSONObject jcondition = new JSONObject(); + try { + if (account != null && account.conditions != null) + jcondition = new JSONObject(account.conditions); + } catch (Throwable ex) { + Log.e(ex); + } + etHost.setText(account == null ? null : account.host); etPort.setText(account == null ? null : Long.toString(account.port)); @@ -715,6 +731,7 @@ public class FragmentPop extends FragmentBase { btnColor.setColor(account == null ? null : account.color); cbSynchronize.setChecked(account == null ? true : account.synchronize); + cbIgnoreSchedule.setChecked(jcondition.optBoolean("ignore_schedule")); cbOnDemand.setChecked(account == null ? false : account.ondemand); cbPrimary.setChecked(account == null ? false : account.primary); @@ -735,16 +752,7 @@ public class FragmentPop extends FragmentBase { ? EntityAccount.DEFAULT_MAX_MESSAGES : account.max_messages)); etInterval.setText(account == null ? "" : Long.toString(account.poll_interval)); - - JSONObject jcondition = new JSONObject(); - try { - if (account != null && account.conditions != null) - jcondition = new JSONObject(account.conditions); - } catch (Throwable ex) { - Log.e(ex); - } cbUnmetered.setChecked(jcondition.optBoolean("unmetered")); - cbIdentity.setChecked(account == null); List folders = getSwipeActions(); @@ -793,6 +801,7 @@ public class FragmentPop extends FragmentBase { tilPassword.setEnabled(false); } + cbIgnoreSchedule.setEnabled(cbSynchronize.isChecked()); cbOnDemand.setEnabled(cbSynchronize.isChecked()); cbPrimary.setEnabled(cbSynchronize.isChecked()); diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java index 73bb602572..bd9dbb27d6 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java +++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java @@ -59,6 +59,8 @@ import com.sun.mail.imap.IMAPStore; import com.sun.mail.imap.protocol.IMAPProtocol; import com.sun.mail.imap.protocol.IMAPResponse; +import org.json.JSONObject; + import java.io.File; import java.io.IOException; import java.text.DateFormat; @@ -1221,17 +1223,32 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences @Override public void delegate() { try { + long now = new Date().getTime(); + long[] schedule = ServiceSynchronize.getSchedule(ServiceSynchronize.this); + boolean scheduled = (schedule == null || (now >= schedule[0] && now < schedule[1])); + + boolean work = false; DB db = DB.getInstance(ServiceSynchronize.this); try { db.beginTransaction(); List accounts = db.account().getPollAccounts(null); for (EntityAccount account : accounts) { - List folders = db.folder().getSynchronizingFolders(account.id); - if (folders.size() > 0) - Collections.sort(folders, folders.get(0).getComparator(ServiceSynchronize.this)); - for (EntityFolder folder : folders) - EntityOperation.poll(ServiceSynchronize.this, folder.id); + JSONObject jcondition = new JSONObject(); + try { + jcondition = new JSONObject(account.conditions); + } catch (Throwable ex) { + Log.e(ex); + } + + if (scheduled || jcondition.optBoolean("ignore_schedule")) { + work = true; + List folders = db.folder().getSynchronizingFolders(account.id); + if (folders.size() > 0) + Collections.sort(folders, folders.get(0).getComparator(ServiceSynchronize.this)); + for (EntityFolder folder : folders) + EntityOperation.poll(ServiceSynchronize.this, folder.id); + } } db.setTransactionSuccessful(); @@ -1239,10 +1256,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences db.endTransaction(); } - long now = new Date().getTime(); - long[] schedule = ServiceSynchronize.getSchedule(ServiceSynchronize.this); - boolean scheduled = (schedule == null || (now >= schedule[0] && now < schedule[1])); - schedule(ServiceSynchronize.this, scheduled, true, null); + schedule(ServiceSynchronize.this, work, true, null); // Prevent service stop eval(ServiceSynchronize.this, "poll"); @@ -2826,7 +2840,8 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences List result = new ArrayList<>(); for (TupleAccountState accountState : accountStates) result.add(new TupleAccountNetworkState( - enabled && (pollInterval == 0 || accountState.isExempted(ServiceSynchronize.this)) && scheduled, + enabled && (pollInterval == 0 || accountState.isExempted(ServiceSynchronize.this)), + scheduled, command, networkState, accountState)); @@ -2899,15 +2914,12 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); am.cancel(pi); - boolean scheduled; - Long at = null; - long[] schedule = getSchedule(context); - if (schedule == null) - scheduled = true; - else { - long now = new Date().getTime(); + long now = new Date().getTime(); + long[] schedule = ServiceSynchronize.getSchedule(context); + boolean scheduled = (schedule == null || (now >= schedule[0] && now < schedule[1])); + + if (schedule != null) { long next = (now < schedule[0] ? schedule[0] : schedule[1]); - scheduled = (now >= schedule[0] && now < schedule[1]); Log.i("Schedule now=" + new Date(now)); Log.i("Schedule start=" + new Date(schedule[0])); @@ -2916,14 +2928,37 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences Log.i("Schedule scheduled=" + scheduled); AlarmManagerCompatEx.setAndAllowWhileIdle(context, am, AlarmManager.RTC_WAKEUP, next, pi); - - if (scheduled && polled) { - at = now + 30 * 1000L; - Log.i("Sync at schedule start=" + new Date(at)); - } } - schedule(context, scheduled, polled, at); + executor.submit(new RunnableEx("schedule") { + @Override + protected void delegate() { + boolean work = false; + DB db = DB.getInstance(context); + List accounts = db.account().getPollAccounts(null); + for (EntityAccount account : accounts) { + JSONObject jcondition = new JSONObject(); + try { + jcondition = new JSONObject(account.conditions); + } catch (Throwable ex) { + Log.e(ex); + } + + if (scheduled || jcondition.optBoolean("ignore_schedule")) { + work = true; + break; + } + } + + Long at = null; + if (scheduled && polled) { + at = now + 30 * 1000L; + Log.i("Sync at schedule start=" + new Date(at)); + } + + schedule(context, work, polled, at); + } + }); } private static void schedule(Context context, boolean scheduled, boolean polled, Long at) { diff --git a/app/src/main/java/eu/faircode/email/TupleAccountNetworkState.java b/app/src/main/java/eu/faircode/email/TupleAccountNetworkState.java index a003fa6aeb..af9532b400 100644 --- a/app/src/main/java/eu/faircode/email/TupleAccountNetworkState.java +++ b/app/src/main/java/eu/faircode/email/TupleAccountNetworkState.java @@ -39,6 +39,7 @@ public class TupleAccountNetworkState { public TupleAccountNetworkState( boolean enabled, + boolean scheduled, @NonNull Bundle command, @NonNull ConnectionHelper.NetworkState networkState, @NonNull TupleAccountState accountState) { @@ -54,6 +55,9 @@ public class TupleAccountNetworkState { } catch (Throwable ex) { Log.e(ex); } + + if (!scheduled && !jconditions.optBoolean("ignore_schedule")) + this.enabled = false; } public boolean canRun() { diff --git a/app/src/main/res/layout/fragment_account.xml b/app/src/main/res/layout/fragment_account.xml index a35ac4b06e..90f08ca767 100644 --- a/app/src/main/res/layout/fragment_account.xml +++ b/app/src/main/res/layout/fragment_account.xml @@ -477,6 +477,15 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/btnAdvanced" /> + + + app:layout_constraintTop_toBottomOf="@id/cbIgnoreSchedule" /> + + + app:layout_constraintTop_toBottomOf="@id/cbIgnoreSchedule" /> Use \'Date\' header (sent time) Changes will be applied to new messages only Connect only via unmetered networks + Sync outside the schedule Add related identity (SMTP server) Check Trust server certificate with fingerprint %1$s diff --git a/metadata/en-US/changelogs/1879.txt b/metadata/en-US/changelogs/1879.txt index 7b63a81fb9..117d25c9a4 100644 --- a/metadata/en-US/changelogs/1879.txt +++ b/metadata/en-US/changelogs/1879.txt @@ -4,6 +4,12 @@ ### [Hulsanpes](https://en.wikipedia.org/wiki/Hulsanpes) +### Next version + +* Added advanced account option to sync outside schedule +* Small improvements and minor bug fixes +* Updated translations + ### 1.1879 - 2022-04-23 * Added warning about airplane mode enabled