Simple email application for Android. Original source code: https://framagit.org/dystopia-project/simple-email
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
5.5 KiB

6 years ago
6 years ago
  1. package eu.faircode.email;
  2. /*
  3. This file is part of FairEmail.
  4. FairEmail is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. NetGuard is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with NetGuard. If not, see <http://www.gnu.org/licenses/>.
  14. Copyright 2018 by Marcel Bokhorst (M66B)
  15. */
  16. import android.content.Context;
  17. import android.os.Bundle;
  18. import android.os.Handler;
  19. import android.util.Log;
  20. import java.util.concurrent.ExecutorService;
  21. import java.util.concurrent.Executors;
  22. import androidx.appcompat.app.AppCompatActivity;
  23. import androidx.fragment.app.Fragment;
  24. import androidx.lifecycle.Lifecycle;
  25. import androidx.lifecycle.LifecycleObserver;
  26. import androidx.lifecycle.LifecycleOwner;
  27. import androidx.lifecycle.LifecycleService;
  28. import androidx.lifecycle.OnLifecycleEvent;
  29. //
  30. // This simple task is simple to use, but it is also simple to cause bugs that can easily lead to crashes
  31. // Make sure to not access any member in any outer scope from onLoad
  32. // Results will not be delivered to destroyed fragments
  33. //
  34. public abstract class SimpleTask<T> implements LifecycleObserver {
  35. private LifecycleOwner owner;
  36. private boolean paused;
  37. private Bundle args;
  38. private Result stored;
  39. private ExecutorService executor = Executors.newCachedThreadPool(Helper.backgroundThreadFactory);
  40. public void load(Context context, LifecycleOwner owner, Bundle args) {
  41. run(context, owner, args);
  42. }
  43. public void load(LifecycleService service, Bundle args) {
  44. run(service, service, args);
  45. }
  46. public void load(AppCompatActivity activity, Bundle args) {
  47. run(activity, activity, args);
  48. }
  49. public void load(final Fragment fragment, Bundle args) {
  50. try {
  51. run(fragment.getContext(), fragment.getViewLifecycleOwner(), args);
  52. } catch (IllegalStateException ex) {
  53. Log.w(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
  54. }
  55. }
  56. @OnLifecycleEvent(Lifecycle.Event.ON_START)
  57. public void onStart() {
  58. Log.i(Helper.TAG, "Start task " + this);
  59. }
  60. @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
  61. public void onStop() {
  62. Log.i(Helper.TAG, "Stop task " + this);
  63. }
  64. @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
  65. public void onResume() {
  66. Log.i(Helper.TAG, "Resume task " + this);
  67. paused = false;
  68. if (stored != null) {
  69. Log.i(Helper.TAG, "Deferred delivery task " + this);
  70. deliver(args, stored);
  71. stored = null;
  72. }
  73. }
  74. @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
  75. public void onPause() {
  76. Log.i(Helper.TAG, "Pause task " + this);
  77. paused = true;
  78. }
  79. @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
  80. public void onCreated() {
  81. Log.i(Helper.TAG, "Created task " + this);
  82. }
  83. @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
  84. public void onDestroyed() {
  85. Log.i(Helper.TAG, "Destroy task " + this);
  86. owner.getLifecycle().removeObserver(this);
  87. owner = null;
  88. paused = true;
  89. args = null;
  90. stored = null;
  91. }
  92. private void run(final Context context, LifecycleOwner owner, final Bundle args) {
  93. this.owner = owner;
  94. this.paused = false;
  95. this.args = null;
  96. this.stored = null;
  97. owner.getLifecycle().addObserver(this);
  98. // Run in background thread
  99. executor.submit(new Runnable() {
  100. @Override
  101. public void run() {
  102. final Result result = new Result();
  103. try {
  104. result.data = onLoad(context, args);
  105. } catch (Throwable ex) {
  106. Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
  107. result.ex = ex;
  108. }
  109. // Run on main thread
  110. new Handler(context.getMainLooper()).post(new Runnable() {
  111. @Override
  112. public void run() {
  113. deliver(args, result);
  114. }
  115. });
  116. }
  117. });
  118. }
  119. private void deliver(Bundle args, Result result) {
  120. if (paused) {
  121. Log.i(Helper.TAG, "Deferring delivery task " + this);
  122. this.args = args;
  123. this.stored = result;
  124. } else {
  125. Log.i(Helper.TAG, "Delivery task " + this);
  126. try {
  127. if (result.ex == null)
  128. onLoaded(args, (T) result.data);
  129. else
  130. onException(args, result.ex);
  131. } catch (Throwable ex) {
  132. Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
  133. } finally {
  134. onDestroyed();
  135. }
  136. }
  137. }
  138. protected T onLoad(Context context, Bundle args) throws Throwable {
  139. // Be careful not to access members in outer scopes
  140. return null;
  141. }
  142. protected void onLoaded(Bundle args, T data) {
  143. }
  144. protected void onException(Bundle args, Throwable ex) {
  145. }
  146. private static class Result {
  147. Throwable ex;
  148. Object data;
  149. }
  150. }