diff --git a/app/src/main/java/eu/faircode/email/FragmentAccount.java b/app/src/main/java/eu/faircode/email/FragmentAccount.java index ca6f247b50..d864af1abc 100644 --- a/app/src/main/java/eu/faircode/email/FragmentAccount.java +++ b/app/src/main/java/eu/faircode/email/FragmentAccount.java @@ -422,6 +422,8 @@ public class FragmentAccount extends FragmentEx { name = host + "/" + user; try { + ServiceSynchronize.stopSynchroneous(getContext(), "save account"); + DB db = DB.getInstance(getContext()); try { db.beginTransaction(); @@ -496,7 +498,7 @@ public class FragmentAccount extends FragmentEx { return null; } finally { - ServiceSynchronize.restart(getContext(), "account"); + ServiceSynchronize.start(getContext()); } } @@ -538,12 +540,15 @@ public class FragmentAccount extends FragmentEx { new SimpleTask() { @Override protected Void onLoad(Context context, Bundle args) { - // To prevent foreign key constraints from triggering - long id = args.getLong("id"); - ServiceSynchronize.stop(context, "delete account"); - DB.getInstance(context).account().deleteAccount(id); - ServiceSynchronize.start(context); - return null; + try { + ServiceSynchronize.stopSynchroneous(getContext(), "delete account"); + + long id = args.getLong("id"); + DB.getInstance(context).account().deleteAccount(id); + return null; + } finally { + ServiceSynchronize.start(getContext()); + } } @Override diff --git a/app/src/main/java/eu/faircode/email/FragmentFolder.java b/app/src/main/java/eu/faircode/email/FragmentFolder.java index f690479c98..010f13e388 100644 --- a/app/src/main/java/eu/faircode/email/FragmentFolder.java +++ b/app/src/main/java/eu/faircode/email/FragmentFolder.java @@ -77,6 +77,8 @@ public class FragmentFolder extends FragmentEx { @Override protected Void onLoad(Context context, Bundle args) { try { + ServiceSynchronize.stopSynchroneous(getContext(), "save folder"); + long id = args.getLong("id"); boolean synchronize = args.getBoolean("synchronize"); String after = args.getString("after"); @@ -99,7 +101,7 @@ public class FragmentFolder extends FragmentEx { return null; } finally { - ServiceSynchronize.restart(getContext(), "folder"); + ServiceSynchronize.start(getContext()); } } diff --git a/app/src/main/java/eu/faircode/email/FragmentIdentity.java b/app/src/main/java/eu/faircode/email/FragmentIdentity.java index 414d8e7e6d..8d1710af83 100644 --- a/app/src/main/java/eu/faircode/email/FragmentIdentity.java +++ b/app/src/main/java/eu/faircode/email/FragmentIdentity.java @@ -253,6 +253,8 @@ public class FragmentIdentity extends FragmentEx { } try { + ServiceSynchronize.stopSynchroneous(getContext(), "save identity"); + DB db = DB.getInstance(getContext()); try { db.beginTransaction(); @@ -288,7 +290,7 @@ public class FragmentIdentity extends FragmentEx { return null; } finally { - ServiceSynchronize.restart(getContext(), "identity"); + ServiceSynchronize.start(getContext()); } } @@ -329,9 +331,15 @@ public class FragmentIdentity extends FragmentEx { new SimpleTask() { @Override protected Void onLoad(Context context, Bundle args) { - long id = args.getLong("id"); - DB.getInstance(context).identity().deleteIdentity(id); - return null; + try { + ServiceSynchronize.stopSynchroneous(getContext(), "delete identity"); + + long id = args.getLong("id"); + DB.getInstance(context).identity().deleteIdentity(id); + return null; + } finally { + ServiceSynchronize.start(getContext()); + } } @Override diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java index 85d4dac9bb..e6f379dbbc 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java +++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java @@ -24,17 +24,21 @@ import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.ServiceConnection; import android.media.RingtoneManager; import android.net.ConnectivityManager; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.Uri; +import android.os.Binder; import android.os.Build; import android.os.Bundle; +import android.os.IBinder; import android.os.SystemClock; import android.preference.PreferenceManager; import android.text.TextUtils; @@ -177,7 +181,7 @@ public class ServiceSynchronize extends LifecycleService { @Override public int onStartCommand(Intent intent, int flags, int startId) { - Log.i(Helper.TAG, "Service start"); + Log.i(Helper.TAG, "Service start intent=" + intent); super.onStartCommand(intent, flags, startId); if (intent != null && "unseen".equals(intent.getAction())) { @@ -1502,15 +1506,73 @@ public class ServiceSynchronize extends LifecycleService { ContextCompat.startForegroundService(context, new Intent(context, ServiceSynchronize.class)); } - public static void stop(Context context, String reason) { - Log.i(Helper.TAG, "Stop because of '" + reason + "'"); - context.stopService(new Intent(context, ServiceSynchronize.class)); + private IBinder binder = new LocalBinder(); + + private class LocalBinder extends Binder { + ServiceSynchronize getService() { + return ServiceSynchronize.this; + } } - public static void restart(Context context, String reason) { - Log.i(Helper.TAG, "Restart because of '" + reason + "'"); - context.stopService(new Intent(context, ServiceSynchronize.class)); - start(context); + @Override + public IBinder onBind(Intent intent) { + return binder; + } + + public void quit() { + Log.i(Helper.TAG, "Service quit"); + stopSelf(); + } + + public static void stopSynchroneous(Context context, String reason) { + Log.i(Helper.TAG, "Stop because of '" + reason + "'"); + + final Object lock = new Object(); + ServiceConnection connection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName componentName, IBinder binder) { + Log.i(Helper.TAG, "Service connected"); + ((LocalBinder) binder).getService().quit(); + synchronized (lock) { + lock.notify(); + } + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + Log.i(Helper.TAG, "Service disconnected"); + synchronized (lock) { + lock.notify(); + } + } + + @Override + public void onBindingDied(ComponentName name) { + Log.i(Helper.TAG, "Service died"); + synchronized (lock) { + lock.notify(); + } + } + }; + + Intent intent = new Intent(context, ServiceSynchronize.class); + boolean exists = context.getApplicationContext().bindService(intent, connection, Context.BIND_AUTO_CREATE); + Log.i(Helper.TAG, "Service exists=" + exists); + + if (exists) { + Log.i(Helper.TAG, "Service stopping"); + try { + synchronized (lock) { + lock.wait(); + } + } catch (InterruptedException ex) { + Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); + } + + context.getApplicationContext().unbindService(connection); + } + + Log.i(Helper.TAG, "Service stopped"); } private class ServiceState {