From d7e73716034d8da7e9af57a87c25464342eaf9b2 Mon Sep 17 00:00:00 2001 From: M66B Date: Sun, 3 Mar 2019 09:09:11 +0000 Subject: [PATCH] Use foreground worker --- app/build.gradle | 4 + .../eu/faircode/email/EntityOperation.java | 4 +- .../eu/faircode/email/ServiceSynchronize.java | 5 +- .../java/eu/faircode/email/ServiceUI.java | 90 ----------- .../eu/faircode/email/WorkerForeground.java | 150 ++++++++++++++++++ 5 files changed, 157 insertions(+), 96 deletions(-) create mode 100644 app/src/main/java/eu/faircode/email/WorkerForeground.java diff --git a/app/build.gradle b/app/build.gradle index d8bc1939db..0c9d08791c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -109,6 +109,7 @@ dependencies { def lifecycle_version = "2.0.0" def room_version = "2.0.0" def paging_version = "2.1.0" + def work_version = "1.0.0-rc02" def billingclient_version = "1.2" def javamail_version = "1.6.3" def jsoup_version = "1.11.3" @@ -150,6 +151,9 @@ dependencies { // https://mvnrepository.com/artifact/androidx.paging/paging-runtime implementation "androidx.paging:paging-runtime:$paging_version" + // https://mvnrepository.com/artifact/android.arch.work/work-runtime + implementation "android.arch.work:work-runtime:$work_version" + // https://developer.android.com/google/play/billing/billing_library_releases_notes implementation "com.android.billingclient:billing:$billingclient_version" diff --git a/app/src/main/java/eu/faircode/email/EntityOperation.java b/app/src/main/java/eu/faircode/email/EntityOperation.java index da65d46b07..6aafd0a0d6 100644 --- a/app/src/main/java/eu/faircode/email/EntityOperation.java +++ b/app/src/main/java/eu/faircode/email/EntityOperation.java @@ -215,7 +215,7 @@ public class EntityOperation { else if (FOREGROUND.contains(name)) { EntityAccount account = db.account().getAccount(message.account); if (account != null && !"connected".equals(account.state)) - ServiceUI.process(context, operation.folder); + WorkerForeground.queue(operation.folder); } } @@ -248,7 +248,7 @@ public class EntityOperation { if (account == null) // Outbox ServiceSend.start(context); else if (foreground && !"connected".equals(account.state)) - ServiceUI.process(context, fid); + WorkerForeground.queue(fid); Log.i("Queued sync folder=" + folder + " foreground=" + foreground); } diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java index bff4ab0f3c..4067c58351 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java +++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java @@ -259,17 +259,14 @@ public class ServiceSynchronize extends LifecycleService { public void notification(StoreEvent e) { try { wlAccount.acquire(); - String type = (e.getMessageType() == StoreEvent.ALERT ? "alert" : "notice"); if (e.getMessageType() == StoreEvent.ALERT) { - Log.w(account.name + " " + type + ": " + e.getMessage()); - EntityLog.log(ServiceSynchronize.this, account.name + " " + type + ": " + e.getMessage()); db.account().setAccountError(account.id, e.getMessage()); Core.reportError( ServiceSynchronize.this, account, null, new Core.AlertException(e.getMessage())); state.error(); } else - Log.i(account.name + " " + type + ": " + e.getMessage()); + Log.i(account.name + " notice: " + e.getMessage()); } finally { wlAccount.release(); } diff --git a/app/src/main/java/eu/faircode/email/ServiceUI.java b/app/src/main/java/eu/faircode/email/ServiceUI.java index c0ecf6f0f0..2e4d08a3b4 100644 --- a/app/src/main/java/eu/faircode/email/ServiceUI.java +++ b/app/src/main/java/eu/faircode/email/ServiceUI.java @@ -14,7 +14,6 @@ import java.util.HashMap; import java.util.Map; import java.util.Properties; -import javax.mail.Folder; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Store; @@ -136,10 +135,6 @@ public class ServiceUI extends IntentService { onSnooze(id); break; - case "process": - onProcessOperations(id); - break; - case "fsync": onFolderSync(id); break; @@ -272,80 +267,6 @@ public class ServiceUI extends IntentService { } } - private void onProcessOperations(long fid) { - DB db = DB.getInstance(this); - - EntityFolder folder = db.folder().getFolder(fid); - if (folder == null) - return; - EntityAccount account = db.account().getAccount(folder.account); - if (account == null) - return; - - Folder ifolder = null; - try { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - boolean debug = (prefs.getBoolean("debug", false) || BuildConfig.BETA_RELEASE); - - String protocol = account.getProtocol(); - - // Get properties - Properties props = MessageHelper.getSessionProperties(account.auth_type, account.realm, account.insecure); - props.put("mail." + protocol + ".separatestoreconnection", "true"); - - // Create session - final Session isession = Session.getInstance(props, null); - isession.setDebug(debug); - - Store istore = accountStore.get(account.id); - if (istore == null || !istore.isConnected()) { - // Connect account - Log.i(account.name + " connecting"); - db.account().setAccountState(account.id, "connecting"); - istore = isession.getStore(protocol); - Helper.connect(this, istore, account); - db.account().setAccountState(account.id, "connected"); - db.account().setAccountConnected(account.id, new Date().getTime()); - db.account().setAccountError(account.id, null); - Log.i(account.name + " connected"); - - accountStore.put(account, istore); - } else - Log.i(account + " reusing connection"); - - // Connect folder - Log.i(folder.name + " connecting"); - db.folder().setFolderState(folder.id, "connecting"); - 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"); - - // Process operations - Core.processOperations(this, account, folder, isession, istore, ifolder, new Core.State()); - - } catch (Throwable ex) { - Log.w(ex); - Core.reportError(this, account, folder, ex); - db.account().setAccountError(account.id, Helper.formatThrowable(ex)); - db.folder().setFolderError(folder.id, Helper.formatThrowable(ex, false)); - } finally { - if (ifolder != null) - try { - Log.i(folder.name + " closing"); - db.folder().setFolderState(folder.id, "closing"); - ifolder.close(); - } catch (MessagingException ex) { - Log.w(ex); - } finally { - Log.i(folder.name + " closed"); - db.folder().setFolderState(folder.id, null); - db.folder().setFolderSyncState(folder.id, null); - } - } - } - private void onFolderSync(long aid) { DB db = DB.getInstance(this); EntityAccount account = db.account().getAccount(aid); @@ -402,17 +323,6 @@ public class ServiceUI extends IntentService { } } - public static void process(Context context, long folder) { - try { - context.startService( - new Intent(context, ServiceUI.class) - .setAction("process:" + folder)); - } catch (IllegalStateException ex) { - Log.w(ex); - // The background service will handle the operation - } - } - public static void fsync(Context context, long account) { try { context.startService( diff --git a/app/src/main/java/eu/faircode/email/WorkerForeground.java b/app/src/main/java/eu/faircode/email/WorkerForeground.java new file mode 100644 index 0000000000..5b69b006b6 --- /dev/null +++ b/app/src/main/java/eu/faircode/email/WorkerForeground.java @@ -0,0 +1,150 @@ +package eu.faircode.email; + +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +import java.util.Date; +import java.util.Properties; + +import javax.mail.Folder; +import javax.mail.MessagingException; +import javax.mail.Session; +import javax.mail.Store; +import javax.mail.event.StoreEvent; +import javax.mail.event.StoreListener; + +import androidx.annotation.NonNull; +import androidx.work.Data; +import androidx.work.OneTimeWorkRequest; +import androidx.work.WorkInfo; +import androidx.work.WorkManager; +import androidx.work.Worker; +import androidx.work.WorkerParameters; + +public class WorkerForeground extends Worker { + public WorkerForeground(@NonNull Context context, @NonNull WorkerParameters args) { + super(context, args); + } + + @NonNull + @Override + public Result doWork() { + long fid = getInputData().getLong("folder", -1); + Log.i("Work folder=" + fid); + + final DB db = DB.getInstance(getApplicationContext()); + + final EntityFolder folder = db.folder().getFolder(fid); + if (folder == null) + return Result.success(); + final EntityAccount account = db.account().getAccount(folder.account); + if (account == null) + return Result.success(); + + Store istore = null; + try { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + boolean debug = (prefs.getBoolean("debug", false) || BuildConfig.BETA_RELEASE); + + String protocol = account.getProtocol(); + + // Get properties + Properties props = MessageHelper.getSessionProperties(account.auth_type, account.realm, account.insecure); + props.put("mail." + protocol + ".separatestoreconnection", "true"); + + // Create session + Session isession = Session.getInstance(props, null); + isession.setDebug(debug); + + // Connect account + Log.i(account.name + " connecting"); + db.account().setAccountState(account.id, "connecting"); + istore = isession.getStore(protocol); + Helper.connect(getApplicationContext(), istore, account); + db.account().setAccountState(account.id, "connected"); + db.account().setAccountConnected(account.id, new Date().getTime()); + db.account().setAccountError(account.id, null); + Log.i(account.name + " connected"); + + // Listen for store events + istore.addStoreListener(new StoreListener() { + @Override + public void notification(StoreEvent e) { + if (e.getMessageType() == StoreEvent.ALERT) { + db.account().setAccountError(account.id, e.getMessage()); + Core.reportError( + getApplicationContext(), account, null, + new Core.AlertException(e.getMessage())); + } else + Log.i(account.name + " notice: " + e.getMessage()); + } + }); + + // 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"); + + // Process operations + Core.processOperations(getApplicationContext(), account, folder, isession, istore, ifolder, new Core.State()); + + } catch (Throwable ex) { + Log.w(ex); + Core.reportError(getApplicationContext(), account, folder, ex); + db.account().setAccountError(account.id, Helper.formatThrowable(ex)); + db.folder().setFolderError(folder.id, Helper.formatThrowable(ex, false)); + } finally { + if (istore != null) + try { + Log.i(account.name + " closing"); + db.account().setAccountState(account.id, "closing"); + db.folder().setFolderState(folder.id, "closing"); + istore.close(); + } catch (MessagingException ex) { + Log.w(ex); + } finally { + Log.i(account.name + " closed"); + db.account().setAccountState(account.id, "closed"); + db.folder().setFolderState(folder.id, null); + db.folder().setFolderSyncState(folder.id, null); + } + } + + return Result.success(); + } + + @Override + public void onStopped() { + Log.i("Worked stopped"); + } + + static void queue(long fid) { + String tag = "folder:" + fid; + Log.i("Queuing work " + tag); + + try { + for (WorkInfo info : WorkManager.getInstance().getWorkInfosByTag(tag).get()) + if (!info.getState().isFinished()) { + Log.i("Work already queued " + tag); + return; + } + } catch (Throwable ex) { + Log.w(ex); + } + + Data data = new Data.Builder().putLong("folder", fid).build(); + OneTimeWorkRequest workRequest = + new OneTimeWorkRequest.Builder(WorkerForeground.class) + .addTag(tag) + .setInputData(data) + .build(); + WorkManager.getInstance().enqueue(workRequest); + + Log.i("Queued work " + tag); + } +}