Added account ignore schedule

This commit is contained in:
M66B 2022-04-23 12:44:25 +02:00
parent bdc5c81669
commit f457849a78
11 changed files with 141 additions and 44 deletions

View File

@ -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

2
FAQ.md
View File

@ -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.

View File

@ -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

View File

@ -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());

View File

@ -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<EntityFolder> 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());

View File

@ -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<EntityAccount> accounts = db.account().getPollAccounts(null);
for (EntityAccount account : accounts) {
List<EntityFolder> 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<EntityFolder> 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<TupleAccountNetworkState> 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<EntityAccount> 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) {

View File

@ -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() {

View File

@ -477,6 +477,15 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnAdvanced" />
<CheckBox
android:id="@+id/cbIgnoreSchedule"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_ignore_schedule"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbSynchronize" />
<CheckBox
android:id="@+id/cbOnDemand"
android:layout_width="wrap_content"
@ -484,7 +493,7 @@
android:layout_marginTop="12dp"
android:text="@string/title_account_ondemand"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbSynchronize" />
app:layout_constraintTop_toBottomOf="@id/cbIgnoreSchedule" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvLeave"
@ -1057,7 +1066,7 @@
android:layout_height="0dp"
app:constraint_referenced_ids="
cbNotify,tvNotifyPro,
cbSynchronize,cbOnDemand,tvLeave,cbPrimary,
cbSynchronize,cbIgnoreSchedule,cbOnDemand,tvLeave,cbPrimary,
cbBrowse,tvBrowseHint,
cbAutoSeen,
tvInterval,etInterval,tvIntervalRemark,

View File

@ -337,6 +337,15 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvColorPro" />
<CheckBox
android:id="@+id/cbIgnoreSchedule"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_ignore_schedule"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbSynchronize" />
<CheckBox
android:id="@+id/cbOnDemand"
android:layout_width="wrap_content"
@ -344,7 +353,7 @@
android:layout_marginTop="12dp"
android:text="@string/title_account_ondemand"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbSynchronize" />
app:layout_constraintTop_toBottomOf="@id/cbIgnoreSchedule" />
<CheckBox
android:id="@+id/cbPrimary"

View File

@ -951,6 +951,7 @@
<string name="title_date_header">Use \'Date\' header (sent time)</string>
<string name="title_date_remark">Changes will be applied to new messages only</string>
<string name="title_unmetered_only">Connect only via unmetered networks</string>
<string name="title_ignore_schedule">Sync outside the schedule</string>
<string name="title_related_identity">Add related identity (SMTP server)</string>
<string name="title_check">Check</string>
<string name="title_trust">Trust server certificate with fingerprint %1$s</string>

View File

@ -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