mirror of https://github.com/M66B/FairEmail.git
Synchronize on demand
This commit is contained in:
parent
c4208d1a61
commit
7b55d4e0fc
2
FAQ.md
2
FAQ.md
|
@ -28,7 +28,7 @@ For authorizing:
|
|||
|
||||
## Planned features
|
||||
|
||||
* Synchronize on demand
|
||||
* ~~Synchronize on demand~~
|
||||
|
||||
Anything on this list is in random order and *might* be added in the near future.
|
||||
|
||||
|
|
|
@ -38,8 +38,6 @@ import android.view.ViewGroup;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -236,7 +234,8 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
|
|||
|
||||
PopupMenu popupMenu = new PopupMenu(context, itemView);
|
||||
|
||||
popupMenu.getMenu().add(Menu.NONE, action_synchronize_now, 1, R.string.title_synchronize_now);
|
||||
popupMenu.getMenu().add(Menu.NONE, action_synchronize_now, 1, R.string.title_synchronize_now)
|
||||
.setEnabled(folder.account != null || "connected".equals(folder.state) /* outbox */);
|
||||
|
||||
if (folder.account != null)
|
||||
popupMenu.getMenu().add(Menu.NONE, action_delete_local, 2, R.string.title_delete_local);
|
||||
|
@ -283,25 +282,33 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
|
|||
args.putLong("account", folder.account == null ? -1 : folder.account);
|
||||
args.putLong("folder", folder.id);
|
||||
|
||||
new SimpleTask<Boolean>() {
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Boolean onExecute(Context context, Bundle args) {
|
||||
protected Void onExecute(Context context, Bundle args) {
|
||||
long aid = args.getLong("account");
|
||||
long fid = args.getLong("folder");
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
EntityOperation.sync(db, fid);
|
||||
try {
|
||||
db.beginTransaction();
|
||||
|
||||
if (aid < 0) // outbox
|
||||
return "connected".equals(db.folder().getFolder(fid).state);
|
||||
else
|
||||
return "connected".equals(db.account().getAccount(aid).state);
|
||||
}
|
||||
if (aid < 0) // outbox
|
||||
EntityOperation.sync(db, fid);
|
||||
else {
|
||||
if ("connected".equals(db.account().getAccount(aid).state))
|
||||
EntityOperation.sync(db, fid);
|
||||
else {
|
||||
db.folder().setFolderSyncState(folder.id, "requested");
|
||||
ServiceSynchronize.sync(context, fid);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, Boolean connected) {
|
||||
if (!connected)
|
||||
Snackbar.make(itemView, R.string.title_sync_queued, Snackbar.LENGTH_LONG).show();
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.text.Collator;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -162,6 +163,17 @@ public class EntityFolder implements Serializable {
|
|||
public EntityFolder() {
|
||||
}
|
||||
|
||||
long getSyncDays() {
|
||||
int days = sync_days;
|
||||
if (last_sync != null) {
|
||||
int ago_days = (int) ((new Date().getTime() - last_sync) / (24 * 3600 * 1000L)) + 1;
|
||||
if (ago_days > days)
|
||||
days = ago_days;
|
||||
}
|
||||
|
||||
return (initialize ? Math.min(DEFAULT_INIT, keep_days) : days);
|
||||
}
|
||||
|
||||
static int getIcon(String type) {
|
||||
if (EntityFolder.INBOX.equals(type))
|
||||
return R.drawable.baseline_move_to_inbox_24;
|
||||
|
|
|
@ -102,15 +102,8 @@ public class EntityOperation {
|
|||
|
||||
EntityFolder folder = db.folder().getFolder(fid);
|
||||
|
||||
int sync_days = folder.sync_days;
|
||||
if (folder.last_sync != null) {
|
||||
int ago_days = (int) ((new Date().getTime() - folder.last_sync) / (24 * 3600 * 1000L)) + 1;
|
||||
if (ago_days > sync_days)
|
||||
sync_days = ago_days;
|
||||
}
|
||||
|
||||
JSONArray jargs = new JSONArray();
|
||||
jargs.put(folder.initialize ? Math.min(EntityFolder.DEFAULT_INIT, folder.keep_days) : sync_days);
|
||||
jargs.put(folder.getSyncDays());
|
||||
jargs.put(folder.keep_days);
|
||||
jargs.put(folder.download);
|
||||
|
||||
|
|
|
@ -487,22 +487,10 @@ public class FragmentMessages extends FragmentBase {
|
|||
args.putLong("folder", folder);
|
||||
|
||||
new SimpleTask<Boolean>() {
|
||||
@Override
|
||||
protected void onPreExecute(Bundle args) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
boolean enabled = prefs.getBoolean("enabled", true);
|
||||
if (!enabled) {
|
||||
prefs.edit().putBoolean("enabled", true).apply();
|
||||
ServiceSynchronize.reload(getContext(), "refresh");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean onExecute(Context context, Bundle args) {
|
||||
long fid = args.getLong("folder");
|
||||
|
||||
boolean connected = false;
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
try {
|
||||
db.beginTransaction();
|
||||
|
@ -518,33 +506,34 @@ public class FragmentMessages extends FragmentBase {
|
|||
folders.add(folder);
|
||||
}
|
||||
|
||||
for (EntityFolder folder : folders) {
|
||||
EntityOperation.sync(db, folder.id);
|
||||
|
||||
boolean now = false;
|
||||
for (EntityFolder folder : folders)
|
||||
if (folder.account == null) { // outbox
|
||||
if ("connected".equals(folder.state))
|
||||
connected = true;
|
||||
now = ("connected".equals(folder.state));
|
||||
EntityOperation.sync(db, folder.id);
|
||||
} else {
|
||||
now = true;
|
||||
EntityAccount account = db.account().getAccount(folder.account);
|
||||
if ("connected".equals(account.state))
|
||||
connected = true;
|
||||
EntityOperation.sync(db, folder.id);
|
||||
else {
|
||||
db.folder().setFolderSyncState(folder.id, "requested");
|
||||
ServiceSynchronize.sync(context, folder.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
|
||||
return now;
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
|
||||
return connected;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, Boolean connected) {
|
||||
if (!connected) {
|
||||
protected void onExecuted(Bundle args, Boolean now) {
|
||||
if (!now)
|
||||
swipeRefresh.setRefreshing(false);
|
||||
Snackbar.make(view, R.string.title_sync_queued, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -343,6 +343,15 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
serviceManager.service_reload(intent.getStringExtra("reason"));
|
||||
break;
|
||||
|
||||
case "synchronize":
|
||||
executor.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronizeOnDemand(Long.parseLong(parts[1]));
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case "summary":
|
||||
case "clear":
|
||||
case "seen":
|
||||
|
@ -2210,6 +2219,77 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
}
|
||||
}
|
||||
|
||||
private void synchronizeOnDemand(long fid) {
|
||||
Log.i("Synchronize on demand folder=" + fid);
|
||||
|
||||
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||
PowerManager.WakeLock wlAccount = pm.newWakeLock(
|
||||
PowerManager.PARTIAL_WAKE_LOCK, BuildConfig.APPLICATION_ID + ":sync." + fid);
|
||||
|
||||
DB db = DB.getInstance(this);
|
||||
EntityFolder folder = null;
|
||||
EntityAccount account = null;
|
||||
|
||||
Store istore = null;
|
||||
try {
|
||||
wlAccount.acquire();
|
||||
|
||||
folder = db.folder().getFolder(fid);
|
||||
account = db.account().getAccount(folder.account);
|
||||
|
||||
// Create session
|
||||
Properties props = MessageHelper.getSessionProperties(account.auth_type, account.realm, account.insecure);
|
||||
final Session isession = Session.getInstance(props, null);
|
||||
isession.setDebug(true);
|
||||
|
||||
// Connect account
|
||||
Log.i(account.name + " connecting");
|
||||
db.account().setAccountState(account.id, "connecting");
|
||||
istore = isession.getStore(account.getProtocol());
|
||||
Helper.connect(this, istore, account);
|
||||
db.account().setAccountState(account.id, "connected");
|
||||
Log.i(account.name + " connected");
|
||||
|
||||
// Connect folder
|
||||
Log.i(folder.name + " connecting");
|
||||
db.folder().setFolderState(folder.id, "connecting");
|
||||
Folder ifolder = istore.getFolder(folder.name);
|
||||
ifolder.open(Folder.READ_WRITE);
|
||||
db.folder().setFolderState(folder.id, "connected");
|
||||
db.folder().setFolderError(folder.id, null);
|
||||
Log.i(folder.name + " connected");
|
||||
|
||||
// Synchronize messages
|
||||
JSONArray jargs = new JSONArray();
|
||||
jargs.put(folder.getSyncDays());
|
||||
jargs.put(folder.keep_days);
|
||||
jargs.put(folder.download);
|
||||
synchronizeMessages(account, folder, (IMAPFolder) ifolder, jargs, new ServiceState());
|
||||
|
||||
} catch (Throwable ex) {
|
||||
db.account().setAccountError(account.id, Helper.formatThrowable(ex));
|
||||
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
|
||||
} finally {
|
||||
if (istore != null) {
|
||||
Log.i(account.name + " closing");
|
||||
db.account().setAccountState(account.id, "closing");
|
||||
db.folder().setFolderState(folder.id, "closing");
|
||||
|
||||
try {
|
||||
istore.close();
|
||||
} catch (MessagingException ex) {
|
||||
Log.e(ex);
|
||||
}
|
||||
|
||||
db.account().setAccountState(account.id, null);
|
||||
db.folder().setFolderState(folder.id, null);
|
||||
Log.i(account.name + " closed");
|
||||
}
|
||||
|
||||
wlAccount.release();
|
||||
}
|
||||
}
|
||||
|
||||
private void synchronizeFolders(EntityAccount account, Store istore, ServiceState state) throws MessagingException {
|
||||
DB db = DB.getInstance(this);
|
||||
try {
|
||||
|
@ -3273,7 +3353,7 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
try {
|
||||
wl.acquire();
|
||||
|
||||
EntityLog.log(ServiceSynchronize.this, "Reload " +
|
||||
EntityLog.log(ServiceSynchronize.this, "Reload" +
|
||||
" stop=" + doStop + " start=" + doStart + " queued=" + queued + " " + reason);
|
||||
|
||||
if (doStop)
|
||||
|
@ -3339,6 +3419,12 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
.putExtra("reason", reason));
|
||||
}
|
||||
|
||||
public static void sync(Context context, long folder) {
|
||||
ContextCompat.startForegroundService(context,
|
||||
new Intent(context, ServiceSynchronize.class)
|
||||
.setAction("synchronize:" + folder));
|
||||
}
|
||||
|
||||
private class ServiceState {
|
||||
private Thread thread;
|
||||
private Semaphore semaphore = new Semaphore(0);
|
||||
|
|
|
@ -353,7 +353,6 @@
|
|||
<string name="title_ask_show_html">Showing the original message can leak privacy sensitive information</string>
|
||||
<string name="title_ask_show_image">Showing images can leak privacy sensitive information</string>
|
||||
<string name="title_ask_edit_ref">Edit reformatted replied/forwarded message text?</string>
|
||||
<string name="title_sync_queued">Synchronization will take place on next account connection</string>
|
||||
<string name="title_fix">Fix</string>
|
||||
|
||||
<string name="title_compose">Compose</string>
|
||||
|
|
Loading…
Reference in New Issue