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.

181 lines
5.5 KiB

6 years ago
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.os.HandlerThread;
  20. import android.util.Log;
  21. import androidx.appcompat.app.AppCompatActivity;
  22. import androidx.fragment.app.Fragment;
  23. import androidx.lifecycle.Lifecycle;
  24. import androidx.lifecycle.LifecycleObserver;
  25. import androidx.lifecycle.LifecycleOwner;
  26. import androidx.lifecycle.LifecycleService;
  27. import androidx.lifecycle.OnLifecycleEvent;
  28. import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
  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 = false;
  37. private Bundle args = null;
  38. private Result stored = null;
  39. private static HandlerThread handlerThread;
  40. private static Handler handler;
  41. static {
  42. handlerThread = new HandlerThread("SimpleTask");
  43. handlerThread.setPriority(THREAD_PRIORITY_BACKGROUND);
  44. handlerThread.start();
  45. handler = new Handler(handlerThread.getLooper());
  46. }
  47. public void load(Context context, LifecycleOwner owner, Bundle args) {
  48. run(context, owner, args);
  49. }
  50. public void load(LifecycleService service, Bundle args) {
  51. run(service, service, args);
  52. }
  53. public void load(AppCompatActivity activity, Bundle args) {
  54. run(activity, activity, args);
  55. }
  56. public void load(final Fragment fragment, Bundle args) {
  57. run(fragment.getContext(), fragment.getViewLifecycleOwner(), args);
  58. }
  59. @OnLifecycleEvent(Lifecycle.Event.ON_START)
  60. public void onStart() {
  61. Log.i(Helper.TAG, "Start task " + this);
  62. }
  63. @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
  64. public void onStop() {
  65. Log.i(Helper.TAG, "Stop task " + this);
  66. }
  67. @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
  68. public void onResume() {
  69. Log.i(Helper.TAG, "Resume task " + this);
  70. paused = false;
  71. if (stored != null) {
  72. Log.i(Helper.TAG, "Deferred delivery task " + this);
  73. deliver(args, stored);
  74. stored = null;
  75. }
  76. }
  77. @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
  78. public void onPause() {
  79. Log.i(Helper.TAG, "Pause task " + this);
  80. paused = true;
  81. }
  82. @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
  83. public void onCreated() {
  84. Log.i(Helper.TAG, "Created task " + this);
  85. }
  86. @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
  87. public void onDestroyed() {
  88. Log.i(Helper.TAG, "Destroy task " + this);
  89. owner.getLifecycle().removeObserver(this);
  90. owner = null;
  91. paused = true;
  92. args = null;
  93. stored = null;
  94. }
  95. private void run(final Context context, LifecycleOwner owner, final Bundle args) {
  96. this.owner = owner;
  97. owner.getLifecycle().addObserver(this);
  98. // Run in background thread
  99. handler.post(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. }