Fixed timing issues

This commit is contained in:
M66B 2019-12-07 20:32:58 +01:00
parent 7f36e108c6
commit 14628c4d22
16 changed files with 232 additions and 130 deletions

View File

@ -349,9 +349,10 @@ public class ActivityEML extends ActivityBase {
imessage.setFlag(Flags.Flag.DRAFT, false);
ifolder.appendMessages(new Message[]{imessage});
EntityOperation.sync(context, inbox.id, true);
}
EntityOperation.sync(context, inbox.id, true);
ServiceSynchronize.eval(context, false, "EML");
}
return account.name + "/" + inbox.name;

View File

@ -282,6 +282,8 @@ public class AdapterAttachment extends RecyclerView.Adapter<AdapterAttachment.Vi
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "attachment");
return null;
}

View File

@ -595,6 +595,7 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
boolean subscribed = args.getBoolean("subscribed");
EntityOperation.subscribe(context, id, subscribed);
ServiceSynchronize.eval(context, false, "subscribed=" + subscribed);
return null;
}

View File

@ -171,6 +171,8 @@ public class AdapterImage extends RecyclerView.Adapter<AdapterImage.ViewHolder>
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "attachment");
return null;
}

View File

@ -2103,6 +2103,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "doubletap");
return null;
}
@ -2265,6 +2267,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "flag");
return null;
}
@ -2516,6 +2520,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "attachment");
return null;
}
@ -2685,6 +2691,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "attachment");
return null;
}
@ -2928,6 +2936,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "outbox/drafts");
if (message.identity != null) {
// Identity can be deleted
NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
@ -3225,6 +3235,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "seen");
return null;
}
@ -3361,6 +3373,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "resync");
return null;
}
@ -3536,6 +3550,9 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
} finally {
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "headers");
return null;
}
@ -3573,6 +3590,9 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
} finally {
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "raw");
return null;
}
@ -4524,6 +4544,8 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "keywords");
return null;
}
@ -4583,11 +4605,22 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
String keyword = args.getString("keyword");
DB db = DB.getInstance(context);
EntityMessage message = db.message().getMessage(id);
if (message == null)
return null;
try {
db.beginTransaction();
EntityMessage message = db.message().getMessage(id);
if (message == null)
return null;
EntityOperation.queue(context, message, EntityOperation.KEYWORD, keyword, true);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "keyword=" + keyword);
EntityOperation.queue(context, message, EntityOperation.KEYWORD, keyword, true);
return null;
}

View File

@ -92,27 +92,6 @@ public class EntityOperation {
static final String SEND = "send";
static final String EXISTS = "exists";
void cleanup(Context context) {
DB db = DB.getInstance(context);
if (message != null)
db.message().setMessageUiHide(message, false);
if (EntityOperation.MOVE.equals(name) ||
EntityOperation.ADD.equals(name) ||
EntityOperation.RAW.equals(name))
try {
JSONArray jargs = new JSONArray(args);
long tmpid = jargs.optLong(2, -1);
if (tmpid < 0)
return;
db.message().deleteMessage(tmpid);
} catch (JSONException ex) {
Log.e(ex);
}
}
static void queue(Context context, EntityMessage message, String name, Object... values) {
DB db = DB.getInstance(context);
@ -316,11 +295,6 @@ public class EntityOperation {
crumb.put("message", Long.toString(op.message));
crumb.put("free", Integer.toString(Log.getFreeMemMb()));
Log.breadcrumb("queued", crumb);
if (SEND.equals(name))
ServiceSend.start(context);
else
ServiceSynchronize.eval(context, false, "operation=" + name);
}
static void queue(Context context, EntityFolder folder, String name, Object... values) {
@ -379,8 +353,6 @@ public class EntityOperation {
if (folder.account == null) // Outbox
ServiceSend.start(context);
else if (foreground)
ServiceSynchronize.eval(context, false, "sync folder=" + fid);
}
static void subscribe(Context context, long fid, boolean subscribe) {
@ -403,6 +375,27 @@ public class EntityOperation {
Log.i("Queued subscribe=" + subscribe + " folder=" + folder);
}
void cleanup(Context context) {
DB db = DB.getInstance(context);
if (message != null)
db.message().setMessageUiHide(message, false);
if (EntityOperation.MOVE.equals(name) ||
EntityOperation.ADD.equals(name) ||
EntityOperation.RAW.equals(name))
try {
JSONArray jargs = new JSONArray(args);
long tmpid = jargs.optLong(2, -1);
if (tmpid < 0)
return;
db.message().deleteMessage(tmpid);
} catch (JSONException ex) {
Log.e(ex);
}
}
@Override
public boolean equals(Object obj) {
if (obj instanceof EntityOperation) {

View File

@ -313,6 +313,7 @@ public class FragmentAccounts extends FragmentBase {
throw new IllegalStateException(context.getString(R.string.title_no_internet));
boolean now = true;
boolean outbox = false;
DB db = DB.getInstance(context);
try {
@ -323,7 +324,9 @@ public class FragmentAccounts extends FragmentBase {
for (EntityFolder folder : folders) {
EntityOperation.sync(context, folder.id, true);
if (folder.account != null) {
if (folder.account == null)
outbox = true;
else {
EntityAccount account = db.account().getAccount(folder.account);
if (account != null && !"connected".equals(account.state))
now = false;
@ -335,6 +338,10 @@ public class FragmentAccounts extends FragmentBase {
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "refresh/accounts");
if (outbox)
ServiceSend.start(context);
if (!now)
throw new IllegalArgumentException(context.getString(R.string.title_no_connection));

View File

@ -3057,6 +3057,8 @@ public class FragmentCompose extends FragmentBase {
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "compose/draft");
return data;
}
@ -3590,6 +3592,8 @@ public class FragmentCompose extends FragmentBase {
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "compose/action");
if (action == R.id.action_send && draft.ui_snoozed != null) {
Log.i("Delayed send id=" + draft.id + " at " + new Date(draft.ui_snoozed));
EntityMessage.snooze(context, draft.id, draft.ui_snoozed);

View File

@ -57,7 +57,6 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import java.util.Collections;
import java.util.List;
import static android.app.Activity.RESULT_OK;
@ -322,6 +321,7 @@ public class FragmentFolders extends FragmentBase {
throw new IllegalStateException(context.getString(R.string.title_no_internet));
boolean now = true;
boolean outbox = false;
DB db = DB.getInstance(context);
try {
@ -333,25 +333,14 @@ public class FragmentFolders extends FragmentBase {
for (EntityFolder folder : folders) {
EntityOperation.sync(context, folder.id, true);
if (folder.account != null) {
if (folder.account == null)
outbox = true;
else {
EntityAccount account = db.account().getAccount(folder.account);
if (account != null && !"connected".equals(account.state))
now = false;
}
}
} else {
// Folder list
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean enabled = prefs.getBoolean("enabled", true);
if (enabled)
ServiceSynchronize.eval(context, true, "refresh folders");
else {
List<EntityFolder> folders = db.folder().getSynchronizingFolders(aid);
if (folders.size() > 0)
Collections.sort(folders, folders.get(0).getComparator(context));
for (EntityFolder folder : folders)
EntityOperation.sync(context, folder.id, false);
}
}
db.setTransactionSuccessful();
@ -359,6 +348,10 @@ public class FragmentFolders extends FragmentBase {
db.endTransaction();
}
ServiceSynchronize.eval(context, aid > 0, "refresh/folders");
if (outbox)
ServiceSend.start(context);
if (!now)
throw new IllegalArgumentException(context.getString(R.string.title_no_connection));
@ -523,6 +516,8 @@ public class FragmentFolders extends FragmentBase {
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "refresh/folder");
if (!now)
throw new IllegalArgumentException(context.getString(R.string.title_no_connection));
@ -613,6 +608,8 @@ public class FragmentFolders extends FragmentBase {
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "delete");
return null;
}

View File

@ -1192,6 +1192,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "refresh");
if (!now)
throw new IllegalArgumentException(context.getString(R.string.title_no_connection));
@ -2029,6 +2031,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "seen");
return null;
}
@ -2162,6 +2166,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "flag");
return null;
}
@ -3479,6 +3485,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "expand");
return null;
}
@ -3617,6 +3625,9 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
} finally {
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "move");
return null;
}
@ -3738,6 +3749,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
} finally {
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "move");
}
}, "messages:movetimeout");
thread.setPriority(THREAD_PRIORITY_BACKGROUND);
@ -4715,6 +4728,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "delete");
return null;
}
@ -4750,6 +4765,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "delete");
return null;
}
@ -4785,6 +4802,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "move");
return null;
}
@ -4843,6 +4862,9 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
EntityOperation.queue(context, message, EntityOperation.FLAG, true, color);
}
});
ServiceSynchronize.eval(context, false, "flag");
return null;
}
@ -4994,6 +5016,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "copy");
return result;
}
@ -5177,6 +5201,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "delete");
return null;
}

View File

@ -177,7 +177,6 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("badge", checked).apply();
ServiceSynchronize.restart(getContext(), "badge");
}
});
@ -185,7 +184,6 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("unseen_ignored", checked).apply();
ServiceSynchronize.restart(getContext(), "unseen_ignored");
}
});

View File

@ -641,6 +641,8 @@ public class Log {
db.endTransaction();
}
ServiceSynchronize.eval(context, false, "debuginfo");
return draft;
}

View File

@ -461,14 +461,16 @@ public class ServiceSend extends ServiceBase {
EntityOperation.queue(this, orphan, EntityOperation.EXISTS);
}
// Reset identity
db.identity().setIdentityConnected(ident.id, new Date().getTime());
db.identity().setIdentityError(ident.id, null);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
// Reset identity
db.identity().setIdentityConnected(ident.id, new Date().getTime());
db.identity().setIdentityError(ident.id, null);
ServiceSynchronize.eval(ServiceSend.this, false, "sent");
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancel("send:" + message.identity, 1);

View File

@ -104,9 +104,11 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
));
private static final List<String> PREF_RELOAD = Collections.unmodifiableList(Arrays.asList(
"metered", "roaming", "rlah",
"socks_enabled", "socks_proxy",
"subscribed_only", "debug"
"metered", "roaming", "rlah", // force reconnect
"socks_enabled", "socks_proxy", // force reconnect
"subscribed_only", // force folder sync
"badge", "unseen_ignored", // force update badge/widget
"debug" // force reconnect
));
static final int PI_ALARM = 1;
@ -153,6 +155,10 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
postValue(result);
}
}
private void postDestroy() {
postValue(null);
}
}
@Override
@ -198,7 +204,8 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
}
});
liveAccountNetworkState.observe(this, new Observer<List<TupleAccountNetworkState>>() {
Log.i("### observe");
liveAccountNetworkState.observeForever(new Observer<List<TupleAccountNetworkState>>() {
boolean running = true;
private List<TupleAccountNetworkState> accountStates = new ArrayList<>();
private Map<TupleAccountNetworkState, Core.State> serviceStates = new Hashtable<>();
@ -206,69 +213,81 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
@Override
public void onChanged(List<TupleAccountNetworkState> accountNetworkStates) {
if (!running) {
Log.i("### not running");
return;
}
if (accountNetworkStates == null) {
for (TupleAccountNetworkState prev : serviceStates.keySet())
stop(prev);
boolean runService = false;
quit();
int connected = 0;
int pending = 0;
for (TupleAccountNetworkState current : accountNetworkStates) {
if (current.accountState.shouldRun(current.enabled))
runService = true;
if ("connected".equals(current.accountState.state))
connected++;
pending += current.accountState.operations;
int index = accountStates.indexOf(current);
if (index < 0) {
if (current.canRun()) {
Log.i("### new " + current);
start(current, current.accountState.isEnabled(current.enabled));
}
} else {
TupleAccountNetworkState prev = accountStates.get(index);
accountStates.remove(index);
Core.State state = serviceStates.get(current);
if (state != null)
state.setNetworkState(current.networkState);
// TODO: reload disconnected account on new network available
// !"connected".equals(current.accountState.state))
if (current.reload ||
prev.canRun() != current.canRun() ||
!prev.accountState.equals(current.accountState)) {
Log.i("### changed " + current +
" reload=" + current.reload +
" run prev=" + prev.canRun() +
" run cur=" + current.canRun() +
" changed=" + !prev.accountState.equals(current.accountState));
if (prev.canRun())
stop(prev);
if (current.canRun())
start(current, current.accountState.isEnabled(current.enabled));
if (current.accountState.tbd != null)
delete(current);
}
accountStates.clear();
serviceStates.clear();
liveAccountNetworkState.removeObserver(this);
} else {
if (!running) {
Log.i("### not running");
return;
}
if (current.accountState.tbd == null)
accountStates.add(current);
}
int connected = 0;
int pending = 0;
boolean runService = false;
for (TupleAccountNetworkState current : accountNetworkStates) {
if (current.accountState.shouldRun(current.enabled))
runService = true;
if ("connected".equals(current.accountState.state))
connected++;
pending += current.accountState.operations;
if (accounts != connected || operations != pending) {
accounts = connected;
operations = pending;
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(Helper.NOTIFICATION_SYNCHRONIZE, getNotificationService(accounts, operations).build());
}
int index = accountStates.indexOf(current);
if (index < 0) {
if (current.canRun()) {
Log.i("### new " + current);
start(current, current.accountState.isEnabled(current.enabled));
}
} else {
TupleAccountNetworkState prev = accountStates.get(index);
accountStates.remove(index);
if (!runService)
exit();
Core.State state = serviceStates.get(current);
if (state != null)
state.setNetworkState(current.networkState);
// TODO: reload disconnected account on new network available
// !"connected".equals(current.accountState.state))
if (current.reload ||
prev.canRun() != current.canRun() ||
!prev.accountState.equals(current.accountState)) {
Log.i("### changed " + current +
" reload=" + current.reload +
" run prev=" + prev.canRun() +
" run cur=" + current.canRun() +
" changed=" + !prev.accountState.equals(current.accountState));
if (prev.canRun())
stop(prev);
if (current.canRun())
start(current, current.accountState.isEnabled(current.enabled));
if (current.accountState.tbd != null)
delete(current);
}
}
if (current.accountState.tbd == null)
accountStates.add(current);
}
if (runService) {
if (accounts != connected || operations != pending) {
accounts = connected;
operations = pending;
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(Helper.NOTIFICATION_SYNCHRONIZE, getNotificationService(accounts, operations).build());
}
} else {
running = false;
stopSelf();
}
}
}
private void start(final TupleAccountNetworkState accountNetworkState, boolean sync) {
@ -359,14 +378,13 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
});
}
private void exit() {
EntityLog.log(ServiceSynchronize.this, "Service exit");
private void quit() {
EntityLog.log(ServiceSynchronize.this, "Service quit");
running = false;
queue.submit(new Runnable() {
@Override
public void run() {
Log.i("### exit");
Log.i("### quit");
DB db = DB.getInstance(ServiceSynchronize.this);
List<EntityOperation> ops = db.operation().getOperations(EntityOperation.SYNC);
@ -374,7 +392,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
db.folder().setFolderSyncState(op.folder, null);
stopSelf();
Log.i("### exited");
Log.i("### quited");
}
});
}
@ -523,7 +541,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
cm.unregisterNetworkCallback(networkCallback);
liveAccountNetworkState.post(new ConnectionHelper.NetworkState());
liveAccountNetworkState.postDestroy();
setUnseen(null);
@ -1486,9 +1504,4 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
new Intent(context, ServiceSynchronize.class)
.setAction("reset"));
}
static void restart(Context context, String reason) {
context.stopService(new Intent(context, ServiceSynchronize.class));
eval(context, false, reason);
}
}

View File

@ -194,6 +194,8 @@ public class ServiceUI extends IntentService {
} finally {
db.endTransaction();
}
ServiceSynchronize.eval(ServiceUI.this, false, "move");
}
private void onMove(long id) {
@ -215,6 +217,8 @@ public class ServiceUI extends IntentService {
} finally {
db.endTransaction();
}
ServiceSynchronize.eval(ServiceUI.this, false, "move");
}
private void onReplyDirect(long id, Intent intent) throws IOException {
@ -273,11 +277,12 @@ public class ServiceUI extends IntentService {
EntityOperation.queue(this, reply, EntityOperation.SEND);
db.setTransactionSuccessful();
ToastEx.makeText(this, R.string.title_queued, Toast.LENGTH_LONG).show();
} finally {
db.endTransaction();
}
ServiceSend.start(ServiceUI.this);
ToastEx.makeText(this, R.string.title_queued, Toast.LENGTH_LONG).show();
}
private void onFlag(long id) {
@ -303,6 +308,8 @@ public class ServiceUI extends IntentService {
} finally {
db.endTransaction();
}
ServiceSynchronize.eval(ServiceUI.this, false, "flag");
}
private void onSeen(long id) {
@ -320,6 +327,8 @@ public class ServiceUI extends IntentService {
} finally {
db.endTransaction();
}
ServiceSynchronize.eval(ServiceUI.this, false, "seen");
}
private void onSnooze(long id) {
@ -376,6 +385,8 @@ public class ServiceUI extends IntentService {
}
private void onWakeup(long id) {
EntityFolder folder;
DB db = DB.getInstance(this);
try {
db.beginTransaction();
@ -384,7 +395,10 @@ public class ServiceUI extends IntentService {
if (message == null)
return;
EntityFolder folder = db.folder().getFolder(message.folder);
folder = db.folder().getFolder(message.folder);
if (folder == null)
return;
if (EntityFolder.OUTBOX.equals(folder.type)) {
Log.i("Delayed send id=" + message.id);
db.message().setMessageSnoozed(message.id, null);
@ -407,6 +421,11 @@ public class ServiceUI extends IntentService {
} finally {
db.endTransaction();
}
if (EntityFolder.OUTBOX.equals(folder.type))
ServiceSend.start(ServiceUI.this);
else
ServiceSynchronize.eval(ServiceUI.this, false, "wakeup");
}
private void onDaily() {

View File

@ -63,6 +63,8 @@ public class WorkerPoll extends Worker {
db.endTransaction();
}
ServiceSynchronize.eval(getApplicationContext(), false, "refresh/poll");
return Result.success();
}