Let outbox show connectivity

pull/50/head
M66B 7 years ago
parent 1e1022a147
commit c4b1963f80

@ -84,7 +84,8 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
} }
private void bindTo(TupleFolderEx folder) { private void bindTo(TupleFolderEx folder) {
ivEdit.setVisibility(EntityFolder.OUTBOX.equals(folder.type) ? View.INVISIBLE : View.VISIBLE); boolean outbox = EntityFolder.OUTBOX.equals(folder.type);
ivEdit.setVisibility(outbox ? View.INVISIBLE : View.VISIBLE);
String name = Helper.localizeFolderName(context, folder.name); String name = Helper.localizeFolderName(context, folder.name);
if (folder.unseen > 0) if (folder.unseen > 0)
@ -113,7 +114,7 @@ public class AdapterFolder extends RecyclerView.Adapter<AdapterFolder.ViewHolder
ivState.setImageResource(R.drawable.baseline_cloud_queue_24); ivState.setImageResource(R.drawable.baseline_cloud_queue_24);
else else
ivState.setImageResource(R.drawable.baseline_cloud_off_24); ivState.setImageResource(R.drawable.baseline_cloud_off_24);
ivState.setVisibility(folder.synchronize ? View.VISIBLE : View.INVISIBLE); ivState.setVisibility(folder.synchronize || outbox ? View.VISIBLE : View.INVISIBLE);
tvError.setText(folder.error); tvError.setText(folder.error);
tvError.setVisibility(folder.error == null ? View.GONE : View.VISIBLE); tvError.setVisibility(folder.error == null ? View.GONE : View.VISIBLE);

@ -422,7 +422,7 @@ public class FragmentAccount extends FragmentEx {
name = host + "/" + user; name = host + "/" + user;
try { try {
ServiceSynchronize.stopSynchroneous(getContext(), "save account"); ServiceSynchronize.stopSynchronous(getContext(), "save account");
DB db = DB.getInstance(getContext()); DB db = DB.getInstance(getContext());
try { try {
@ -541,7 +541,7 @@ public class FragmentAccount extends FragmentEx {
@Override @Override
protected Void onLoad(Context context, Bundle args) { protected Void onLoad(Context context, Bundle args) {
try { try {
ServiceSynchronize.stopSynchroneous(getContext(), "delete account"); ServiceSynchronize.stopSynchronous(getContext(), "delete account");
long id = args.getLong("id"); long id = args.getLong("id");
DB.getInstance(context).account().deleteAccount(id); DB.getInstance(context).account().deleteAccount(id);

@ -77,7 +77,7 @@ public class FragmentFolder extends FragmentEx {
@Override @Override
protected Void onLoad(Context context, Bundle args) { protected Void onLoad(Context context, Bundle args) {
try { try {
ServiceSynchronize.stopSynchroneous(getContext(), "save folder"); ServiceSynchronize.stopSynchronous(getContext(), "save folder");
long id = args.getLong("id"); long id = args.getLong("id");
boolean synchronize = args.getBoolean("synchronize"); boolean synchronize = args.getBoolean("synchronize");

@ -253,7 +253,7 @@ public class FragmentIdentity extends FragmentEx {
} }
try { try {
ServiceSynchronize.stopSynchroneous(getContext(), "save identity"); ServiceSynchronize.stopSynchronous(getContext(), "save identity");
DB db = DB.getInstance(getContext()); DB db = DB.getInstance(getContext());
try { try {
@ -332,7 +332,7 @@ public class FragmentIdentity extends FragmentEx {
@Override @Override
protected Void onLoad(Context context, Bundle args) { protected Void onLoad(Context context, Bundle args) {
try { try {
ServiceSynchronize.stopSynchroneous(getContext(), "delete identity"); ServiceSynchronize.stopSynchronous(getContext(), "delete identity");
long id = args.getLong("id"); long id = args.getLong("id");
DB.getInstance(context).identity().deleteIdentity(id); DB.getInstance(context).identity().deleteIdentity(id);

@ -71,6 +71,7 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import javax.mail.Address; import javax.mail.Address;
import javax.mail.FetchProfile; import javax.mail.FetchProfile;
@ -107,7 +108,6 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
public class ServiceSynchronize extends LifecycleService { public class ServiceSynchronize extends LifecycleService {
private final Object lock = new Object(); private final Object lock = new Object();
private ExecutorService executor = Executors.newSingleThreadExecutor();
private static final int NOTIFICATION_SYNCHRONIZE = 1; private static final int NOTIFICATION_SYNCHRONIZE = 1;
private static final int NOTIFICATION_UNSEEN = 2; private static final int NOTIFICATION_UNSEEN = 2;
@ -326,6 +326,8 @@ public class ServiceSynchronize extends LifecycleService {
private void monitorAccount(final EntityAccount account, final ServiceState state) { private void monitorAccount(final EntityAccount account, final ServiceState state) {
final List<Thread> threads = new ArrayList<>(); final List<Thread> threads = new ArrayList<>();
final ExecutorService executor = Executors.newSingleThreadExecutor();
Log.i(Helper.TAG, account.name + " start"); Log.i(Helper.TAG, account.name + " start");
final DB db = DB.getInstance(ServiceSynchronize.this); final DB db = DB.getInstance(ServiceSynchronize.this);
@ -520,7 +522,7 @@ public class ServiceSynchronize extends LifecycleService {
} }
} }
BroadcastReceiver processReceiver = new BroadcastReceiver() { private BroadcastReceiver processReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
final long fid = intent.getLongExtra("folder", -1); final long fid = intent.getLongExtra("folder", -1);
@ -533,41 +535,45 @@ public class ServiceSynchronize extends LifecycleService {
final IMAPFolder ffolder = ifolder; final IMAPFolder ffolder = ifolder;
Log.i(Helper.TAG, "run operations folder=" + fid + " offline=" + shouldClose); Log.i(Helper.TAG, "run operations folder=" + fid + " offline=" + shouldClose);
executor.submit(new Runnable() { try {
@Override executor.submit(new Runnable() {
public void run() { @Override
DB db = DB.getInstance(ServiceSynchronize.this); public void run() {
EntityFolder folder = db.folder().getFolder(fid); DB db = DB.getInstance(ServiceSynchronize.this);
IMAPFolder ifolder = ffolder; EntityFolder folder = db.folder().getFolder(fid);
try { IMAPFolder ifolder = ffolder;
Log.i(Helper.TAG, folder.name + " start operations"); try {
Log.i(Helper.TAG, folder.name + " start operations");
if (ifolder == null) { if (ifolder == null) {
// Prevent unnecessary folder connections // Prevent unnecessary folder connections
if (db.operation().getOperationCount(fid) == 0) if (db.operation().getOperationCount(fid) == 0)
return; return;
ifolder = (IMAPFolder) fstore.getFolder(folder.name); ifolder = (IMAPFolder) fstore.getFolder(folder.name);
ifolder.open(Folder.READ_WRITE); ifolder.open(Folder.READ_WRITE);
} }
processOperations(folder, isession, fstore, ifolder); processOperations(folder, isession, fstore, ifolder);
} catch (Throwable ex) { } catch (Throwable ex) {
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex)); Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
reportError(account.name, folder.name, ex); reportError(account.name, folder.name, ex);
} finally { } finally {
if (shouldClose) if (shouldClose)
if (ifolder != null && ifolder.isOpen()) { if (ifolder != null && ifolder.isOpen()) {
try { try {
ifolder.close(false); ifolder.close(false);
} catch (MessagingException ex) { } catch (MessagingException ex) {
Log.w(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex)); Log.w(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
}
} }
} Log.i(Helper.TAG, folder.name + " stop operations");
Log.i(Helper.TAG, folder.name + " stop operations"); }
} }
} });
}); } catch (RejectedExecutionException ex) {
Log.w(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
}
} }
}; };
}); });
@ -642,6 +648,7 @@ public class ServiceSynchronize extends LifecycleService {
} }
} }
threads.clear(); threads.clear();
executor.shutdown();
Log.i(Helper.TAG, account.name + " stopped"); Log.i(Helper.TAG, account.name + " stopped");
} }
@ -1361,6 +1368,7 @@ public class ServiceSynchronize extends LifecycleService {
ServiceState state = new ServiceState(); ServiceState state = new ServiceState();
private Thread main; private Thread main;
private EntityFolder outbox = null; private EntityFolder outbox = null;
private ExecutorService executor = Executors.newSingleThreadExecutor();
@Override @Override
public void onAvailable(Network network) { public void onAvailable(Network network) {
@ -1376,57 +1384,71 @@ public class ServiceSynchronize extends LifecycleService {
@Override @Override
public void run() { public void run() {
DB db = DB.getInstance(ServiceSynchronize.this); DB db = DB.getInstance(ServiceSynchronize.this);
try { try {
outbox = db.folder().getOutbox();
if (outbox == null) {
Log.i(Helper.TAG, "No outbox, halt");
stopSelf();
return;
}
List<EntityAccount> accounts = db.account().getAccounts(true); List<EntityAccount> accounts = db.account().getAccounts(true);
if (accounts.size() == 0) { if (accounts.size() == 0) {
Log.i(Helper.TAG, "No accounts, halt"); Log.i(Helper.TAG, "No accounts, halt");
stopSelf(); stopSelf();
} else return;
for (final EntityAccount account : accounts) { }
Log.i(Helper.TAG, account.host + "/" + account.user + " run");
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
monitorAccount(account, state);
} catch (Throwable ex) {
// Fall-safe
Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
}
}
}, "sync.account." + account.id);
t.start();
threads.add(t);
}
} catch (Throwable ex) {
// Failsafe
Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
}
outbox = db.folder().getOutbox(); // Start monitoring outbox
if (outbox != null) try {
IntentFilter f = new IntentFilter(ACTION_PROCESS_OPERATIONS); IntentFilter f = new IntentFilter(ACTION_PROCESS_OPERATIONS);
f.addDataType("account/outbox"); f.addDataType("account/outbox");
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(ServiceSynchronize.this); LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(ServiceSynchronize.this);
lbm.registerReceiver(outboxReceiver, f); lbm.registerReceiver(outboxReceiver, f);
db.folder().setFolderState(outbox.id, "connected");
lbm.sendBroadcast(new Intent(ACTION_PROCESS_OPERATIONS) lbm.sendBroadcast(new Intent(ACTION_PROCESS_OPERATIONS)
.setType("account/outbox") .setType("account/outbox")
.putExtra("folder", outbox.id)); .putExtra("folder", outbox.id));
// Start monitoring accounts
for (final EntityAccount account : accounts) {
Log.i(Helper.TAG, account.host + "/" + account.user + " run");
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
monitorAccount(account, state);
} catch (Throwable ex) {
// Fall-safe
Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
}
}
}, "sync.account." + account.id);
t.start();
threads.add(t);
}
// Stop monitoring accounts
for (Thread t : threads)
try {
Log.i(Helper.TAG, "Joining " + t.getName());
t.join();
Log.i(Helper.TAG, "Joined " + t.getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
threads.clear();
executor.shutdown();
// Stop monitoring outbox
lbm.unregisterReceiver(outboxReceiver);
Log.i(Helper.TAG, outbox.name + " unlisten operations");
db.folder().setFolderState(outbox.id, null);
} catch (Throwable ex) { } catch (Throwable ex) {
// Fail-safe
Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
} }
for (Thread t : threads)
try {
Log.i(Helper.TAG, "Joining " + t.getName());
t.join();
Log.i(Helper.TAG, "Joined " + t.getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
threads.clear();
} }
}, "sync.main"); }, "sync.main");
main.start(); main.start();
@ -1441,12 +1463,6 @@ public class ServiceSynchronize extends LifecycleService {
state.notifyAll(); state.notifyAll();
} }
if (outbox != null) {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(ServiceSynchronize.this);
lbm.unregisterReceiver(outboxReceiver);
Log.i(Helper.TAG, outbox.name + " unlisten operations");
}
try { try {
Log.i(Helper.TAG, "Joining " + main.getName()); Log.i(Helper.TAG, "Joining " + main.getName());
main.join(); main.join();
@ -1454,27 +1470,32 @@ public class ServiceSynchronize extends LifecycleService {
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
} }
main = null; main = null;
} }
BroadcastReceiver outboxReceiver = new BroadcastReceiver() { private BroadcastReceiver outboxReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
Log.i(Helper.TAG, outbox.name + " run operations"); Log.i(Helper.TAG, outbox.name + " run operations");
executor.submit(new Runnable() { try {
@Override executor.submit(new Runnable() {
public void run() { @Override
try { public void run() {
Log.i(Helper.TAG, outbox.name + " start operations"); try {
processOperations(outbox, null, null, null); Log.i(Helper.TAG, outbox.name + " start operations");
} catch (Throwable ex) { processOperations(outbox, null, null, null);
Log.e(Helper.TAG, outbox.name + " " + ex + "\n" + Log.getStackTraceString(ex)); } catch (Throwable ex) {
reportError(null, outbox.name, ex); Log.e(Helper.TAG, outbox.name + " " + ex + "\n" + Log.getStackTraceString(ex));
} finally { reportError(null, outbox.name, ex);
Log.i(Helper.TAG, outbox.name + " end operations"); } finally {
Log.i(Helper.TAG, outbox.name + " end operations");
}
} }
} });
}); } catch (RejectedExecutionException ex) {
Log.w(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
}
} }
}; };
}; };
@ -1524,7 +1545,7 @@ public class ServiceSynchronize extends LifecycleService {
stopSelf(); stopSelf();
} }
public static void stopSynchroneous(Context context, String reason) { public static void stopSynchronous(Context context, String reason) {
Log.i(Helper.TAG, "Stop because of '" + reason + "'"); Log.i(Helper.TAG, "Stop because of '" + reason + "'");
final Object lock = new Object(); final Object lock = new Object();

Loading…
Cancel
Save