Unified executor model

pull/210/head
M66B 2 years ago
parent 101371854b
commit 6988d4c552

@ -37,10 +37,8 @@ import androidx.constraintlayout.widget.Group;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
public class ActivityAnswer extends ActivityBase {
private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "answer");
@Override
@RequiresApi(api = Build.VERSION_CODES.M)
@ -71,7 +69,7 @@ public class ActivityAnswer extends ActivityBase {
final Context context = adapterView.getContext();
EntityAnswer answer = (EntityAnswer) adapterView.getAdapter().getItem(pos);
executor.submit(new Runnable() {
Helper.getParallelExecutor().submit(new Runnable() {
@Override
public void run() {
try {

@ -1401,9 +1401,6 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
continue;
if ("query_threads".equals(key))
continue;
// Prevent restart
if ("secure".equals(key) ||
"load_emoji".equals(key) ||

@ -59,7 +59,6 @@ import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
public class AdapterContact extends RecyclerView.Adapter<AdapterContact.ViewHolder> {
private Fragment parentFragment;
@ -80,9 +79,6 @@ public class AdapterContact extends RecyclerView.Adapter<AdapterContact.ViewHold
private NumberFormat NF = NumberFormat.getNumberInstance();
private static final ExecutorService executor =
Helper.getBackgroundExecutor(1, "contacts");
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
private View view;
private ImageView ivType;
@ -470,7 +466,7 @@ public class AdapterContact extends RecyclerView.Adapter<AdapterContact.ViewHold
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(parentFragment.getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(context, owner, new Bundle(), "contacts:filter");
}.serial().execute(context, owner, new Bundle(), "contacts:filter");
}
public void search(String query) {

@ -41,7 +41,6 @@ import androidx.recyclerview.widget.RecyclerView;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
public class AdapterLog extends RecyclerView.Adapter<AdapterLog.ViewHolder> {
private Fragment parentFragment;
@ -58,9 +57,6 @@ public class AdapterLog extends RecyclerView.Adapter<AdapterLog.ViewHolder> {
private DateFormat TF;
private static final ExecutorService executor =
Helper.getBackgroundExecutor(1, "contacts");
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView tvTime;
private TextView tvData;
@ -174,7 +170,7 @@ public class AdapterLog extends RecyclerView.Adapter<AdapterLog.ViewHolder> {
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(parentFragment.getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(context, owner, new Bundle(), "logs:filter");
}.serial().execute(context, owner, new Bundle(), "logs:filter");
}
public void setTypes(@NonNull List<EntityLog.Type> types) {

@ -334,9 +334,6 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
private DateFormat TF;
private DateFormat DTF;
private static final ExecutorService executor =
Helper.getBackgroundExecutor(2, "differ");
private static final int MAX_RECIPIENTS_COMPACT = 3;
private static final int MAX_RECIPIENTS_NORMAL = 7;
@ -7806,7 +7803,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
};
AsyncDifferConfig<TupleMessageEx> config = new AsyncDifferConfig.Builder<>(callback)
.setBackgroundThreadExecutor(executor)
.setBackgroundThreadExecutor(Helper.getParallelExecutor())
.build();
this.differ = new AsyncPagedListDiffer<>(new AdapterListUpdateCallback(this), config);
this.differ.addPagedListListener(new AsyncPagedListDiffer.PagedListListener<TupleMessageEx>() {

@ -59,7 +59,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
@ -99,7 +98,6 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
private IBoundaryCallbackMessages intf;
private State state;
private final ExecutorService executor = Helper.getBackgroundExecutor(1, "boundary");
private static final int SEARCH_LIMIT_DEVICE = 1000;
@ -151,7 +149,7 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
}
void retry() {
executor.submit(new Runnable() {
Helper.getSerialExecutor().submit(new Runnable() {
@Override
public void run() {
close(state, true);
@ -168,7 +166,7 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
state.queued.incrementAndGet();
Log.i("Boundary queued +" + state.queued.get());
executor.submit(new Runnable() {
Helper.getSerialExecutor().submit(new Runnable() {
@Override
public void run() {
Helper.gc();
@ -895,7 +893,7 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
this.intf = null;
Log.i("Boundary destroy");
executor.submit(new Runnable() {
Helper.getSerialExecutor().submit(new Runnable() {
@Override
public void run() {
close(state, true);

@ -75,7 +75,6 @@ import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import javax.mail.Address;
@ -101,12 +100,6 @@ public class ContactInfo {
private static Map<String, Lookup> emailLookup = new ConcurrentHashMap<>();
private static final Map<String, ContactInfo> emailContactInfo = new HashMap<>();
private static final ExecutorService executorLookup =
Helper.getBackgroundExecutor(1, "contact");
private static final ExecutorService executorFavicon =
Helper.getBackgroundExecutor(0, "favicon");
private static final int GENERATED_ICON_SIZE = 48; // dp
private static final int FAVICON_ICON_SIZE = 64; // dp
private static final int FAVICON_CONNECT_TIMEOUT = 5 * 1000; // milliseconds
@ -207,7 +200,7 @@ public class ContactInfo {
for (String type : new String[]{"favicons", "generated"}) {
final File dir = new File(context.getFilesDir(), type);
executorFavicon.submit(new Runnable() {
Helper.getParallelExecutor().submit(new Runnable() {
@Override
public void run() {
try {
@ -381,7 +374,7 @@ public class ContactInfo {
List<Future<Favicon>> futures = new ArrayList<>();
if (bimi)
futures.add(executorFavicon.submit(new Callable<Favicon>() {
futures.add(Helper.getParallelExecutor().submit(new Callable<Favicon>() {
@Override
public Favicon call() throws Exception {
Pair<Bitmap, Boolean> bimi =
@ -391,9 +384,9 @@ public class ContactInfo {
}));
if (gravatars)
futures.add(executorFavicon.submit(Avatar.getGravatar(email, scaleToPixels, context)));
futures.add(Helper.getParallelExecutor().submit(Avatar.getGravatar(email, scaleToPixels, context)));
if (libravatars)
futures.add(executorFavicon.submit(Avatar.getLibravatar(email, scaleToPixels, context)));
futures.add(Helper.getParallelExecutor().submit(Avatar.getLibravatar(email, scaleToPixels, context)));
if (favicons) {
String host = domain;
@ -402,7 +395,7 @@ public class ContactInfo {
while (host.indexOf('.') > 0) {
final URL base = new URL("https://" + host);
futures.add(executorFavicon.submit(new Callable<Favicon>() {
futures.add(Helper.getParallelExecutor().submit(new Callable<Favicon>() {
@Override
public Favicon call() throws Exception {
return parseFavicon(base, scaleToPixels, context);
@ -420,7 +413,7 @@ public class ContactInfo {
final URL base = new URL("https://" + host);
for (String name : FIXED_FAVICONS)
futures.add(executorFavicon.submit(new Callable<Favicon>() {
futures.add(Helper.getParallelExecutor().submit(new Callable<Favicon>() {
@Override
public Favicon call() throws Exception {
return getFavicon(new URL(base, name), null, scaleToPixels, context);
@ -752,7 +745,7 @@ public class ContactInfo {
continue;
final URL url = new URL(base, favicon);
futures.add(executorFavicon.submit(new Callable<Pair<Favicon, URL>>() {
futures.add(Helper.getParallelExecutor().submit(new Callable<Pair<Favicon, URL>>() {
@Override
public Pair<Favicon, URL> call() throws Exception {
return new Pair(getFavicon(url, img.attr("type"), scaleToPixels, context), url);
@ -901,7 +894,7 @@ public class ContactInfo {
@Override
public void onChange(boolean selfChange, Uri uri) {
Log.i("Contact changed uri=" + uri);
executorLookup.submit(new Runnable() {
Helper.getSerialExecutor().submit(new Runnable() {
@Override
public void run() {
try {
@ -914,7 +907,7 @@ public class ContactInfo {
}
};
executorLookup.submit(new Runnable() {
Helper.getSerialExecutor().submit(new Runnable() {
@Override
public void run() {
try {

@ -41,7 +41,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import javax.mail.Address;
import javax.mail.internet.InternetAddress;
@ -363,7 +362,7 @@ public abstract class DB extends RoomDatabase {
sInstance = migrate(sContext, getBuilder(sContext)).build();
sInstance.getQueryExecutor().execute(new Runnable() {
Helper.getSerialExecutor().execute(new Runnable() {
@Override
public void run() {
checkEmergencyBackup(sContext);
@ -399,17 +398,14 @@ public abstract class DB extends RoomDatabase {
private static RoomDatabase.Builder<DB> getBuilder(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
int threads = prefs.getInt("query_threads", DEFAULT_QUERY_THREADS);
boolean wal = prefs.getBoolean("wal", true);
Log.i("DB query threads=" + threads + " wal=" + wal);
ExecutorService executorQuery = Helper.getBackgroundExecutor(threads, "query");
ExecutorService executorTransaction = Helper.getBackgroundExecutor(0, "transaction");
Log.i("DB wal=" + wal);
RoomDatabase.Builder<DB> builder = Room
.databaseBuilder(context, DB.class, DB_NAME)
//.openHelperFactory(new RequerySQLiteOpenHelperFactory())
.setQueryExecutor(executorQuery)
.setTransactionExecutor(executorTransaction)
//.setQueryExecutor()
.setTransactionExecutor(Helper.getParallelExecutor())
.setJournalMode(wal ? JournalMode.WRITE_AHEAD_LOGGING : JournalMode.TRUNCATE) // using the latest sqlite
.addCallback(new Callback() {
@Override
@ -486,7 +482,7 @@ public abstract class DB extends RoomDatabase {
public void onQuery(@NonNull String sqlQuery, @NonNull List<Object> bindArgs) {
Log.i("query=" + sqlQuery);
}
}, executorQuery);
}, Helper.getParallelExecutor());
return builder;
}
@ -2611,7 +2607,7 @@ public abstract class DB extends RoomDatabase {
public static void checkpoint(Context context) {
// https://www.sqlite.org/pragma.html#pragma_wal_checkpoint
DB db = getInstance(context);
db.getQueryExecutor().execute(new Runnable() {
Helper.getParallelExecutor().execute(new Runnable() {
@Override
public void run() {
try {
@ -2641,7 +2637,7 @@ public abstract class DB extends RoomDatabase {
public static void shrinkMemory(Context context) {
DB db = getInstance(context);
db.getQueryExecutor().execute(new Runnable() {
Helper.getParallelExecutor().execute(new Runnable() {
@Override
public void run() {
try {

@ -40,13 +40,11 @@ import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import javax.net.ssl.HttpsURLConnection;
public class DisconnectBlacklist {
private static final Map<String, List<String>> map = new HashMap<>();
private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "disconnect");
private final static int FETCH_TIMEOUT = 20 * 1000; // milliseconds
private final static String LIST = "https://raw.githubusercontent.com/disconnectme/disconnect-tracking-protection/master/services.json";
@ -54,7 +52,7 @@ public class DisconnectBlacklist {
static void init(Context context) {
final File file = getFile(context);
executor.submit(new Runnable() {
Helper.getSerialExecutor().submit(new Runnable() {
@Override
public void run() {
try {

@ -59,7 +59,6 @@ import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import java.util.List;
import java.util.concurrent.ExecutorService;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
@ -78,9 +77,6 @@ public class EditTextCompose extends FixedEditText {
private int quoteGap;
private int quoteStripe;
private static final ExecutorService executor =
Helper.getBackgroundExecutor(1, "paste");
public EditTextCompose(Context context) {
super(context);
init(context);
@ -371,7 +367,7 @@ public class EditTextCompose extends FixedEditText {
if (snippet.id.equals(id)) {
String html = snippet.getHtml(context, to);
executor.submit(new Runnable() {
Helper.getParallelExecutor().submit(new Runnable() {
@Override
public void run() {
try {
@ -418,7 +414,7 @@ public class EditTextCompose extends FixedEditText {
});
DB db = DB.getInstance(context);
executor.submit(new Runnable() {
Helper.getParallelExecutor().submit(new Runnable() {
@Override
public void run() {
try {
@ -527,7 +523,7 @@ public class EditTextCompose extends FixedEditText {
} else
html = h;
executor.submit(new Runnable() {
Helper.getParallelExecutor().submit(new Runnable() {
@Override
public void run() {
try {

@ -59,7 +59,6 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import javax.mail.Address;
import javax.mail.internet.AddressException;
@ -73,8 +72,6 @@ public class EditTextMultiAutoComplete extends AppCompatMultiAutoCompleteTextVie
private Tokenizer tokenizer;
private Map<String, Integer> encryption = new ConcurrentHashMap<>();
private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "chips");
private static int[] icons = new int[]{
R.drawable.twotone_vpn_key_24_p,
R.drawable.twotone_vpn_key_24_s,
@ -339,7 +336,7 @@ public class EditTextMultiAutoComplete extends AppCompatMultiAutoCompleteTextVie
Integer has = encryption.get(email);
if (has == null) {
final List<Address> recipient = Arrays.asList(new Address[]{parsed[0]});
executor.submit(new Runnable() {
Helper.getParallelExecutor().submit(new Runnable() {
@Override
public void run() {
try {

@ -67,7 +67,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import javax.net.SocketFactory;
@ -103,8 +102,6 @@ public class EmailProvider implements Parcelable {
enum UserType {LOCAL, EMAIL, VALUE}
private static List<EmailProvider> imported;
private static final ExecutorService executor =
Helper.getBackgroundExecutor(0, "provider");
private static final int SCAN_TIMEOUT = 15 * 1000; // milliseconds
private static final int ISPDB_TIMEOUT = 15 * 1000; // milliseconds
@ -132,7 +129,7 @@ public class EmailProvider implements Parcelable {
}
static void init(Context context) {
executor.submit(new Runnable() {
Helper.getSerialExecutor().submit(new Runnable() {
@Override
public void run() {
try {
@ -1102,7 +1099,7 @@ public class EmailProvider implements Parcelable {
private Future<Boolean> getReachable(Context context) {
Log.i("Scanning " + this);
return executor.submit(new Callable<Boolean>() {
return Helper.getParallelExecutor().submit(new Callable<Boolean>() {
// Returns:
// false: closed
// true: listening

@ -73,7 +73,6 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.regex.Pattern;
import javax.mail.AuthenticationFailedException;
@ -117,8 +116,6 @@ public class EmailService implements AutoCloseable {
private ServiceAuthenticator authenticator;
private RingBuffer<String> breadcrumbs;
private ExecutorService executor = Helper.getBackgroundExecutor(0, "mail");
static final int PURPOSE_CHECK = 1;
static final int PURPOSE_USE = 2;
static final int PURPOSE_SEARCH = 3;
@ -207,7 +204,7 @@ public class EmailService implements AutoCloseable {
" use_top=" + use_top);
properties.put("mail.event.scope", "folder");
properties.put("mail.event.executor", executor);
properties.put("mail.event.executor", Helper.getParallelExecutor());
if (!auth_plain)
properties.put("mail." + protocol + ".auth.plain.disable", "true");

@ -32,7 +32,6 @@ import androidx.room.PrimaryKey;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
@Entity(
tableName = EntityLog.TABLE_NAME,
@ -67,9 +66,6 @@ public class EntityLog {
public enum Type {General, Statistics, Scheduling, Network, Account, Protocol, Classification, Notification, Rules, Debug}
private static final ExecutorService executor =
Helper.getBackgroundExecutor(1, "log");
static void log(final Context context, String data) {
log(context, Type.General, data);
}
@ -139,7 +135,7 @@ public class EntityLog {
final DB db = DB.getInstance(context);
final Context acontext = context.getApplicationContext();
executor.submit(new Runnable() {
Helper.getSerialExecutor().submit(new Runnable() {
@Override
public void run() {
// Check available storage space
@ -181,7 +177,7 @@ public class EntityLog {
static void clear(final Context context) {
final Context acontext = context.getApplicationContext();
executor.submit(new Runnable() {
Helper.getParallelExecutor().submit(new Runnable() {
@Override
public void run() {
cleanup(acontext, new Date().getTime());

@ -57,7 +57,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.regex.Pattern;
import javax.mail.Address;
@ -130,8 +129,6 @@ public class EntityRule {
private static final String JSOUP_PREFIX = "jsoup:";
private static final long SEND_DELAY = 5000L; // milliseconds
private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "rule");
static boolean needsHeaders(EntityMessage message, List<EntityRule> rules) {
return needs(rules, "header");
}
@ -760,7 +757,7 @@ public class EntityRule {
return true;
}
executor.submit(new Runnable() {
Helper.getSerialExecutor().submit(new Runnable() {
@Override
public void run() {
try {
@ -982,7 +979,7 @@ public class EntityRule {
return true;
}
executor.submit(new Runnable() {
Helper.getSerialExecutor().submit(new Runnable() {
@Override
public void run() {
try {

@ -78,14 +78,10 @@ import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.method.ArrowKeyMovementMethod;
import android.text.style.BackgroundColorSpan;
import android.text.style.BulletSpan;
import android.text.style.CharacterStyle;
import android.text.style.ImageSpan;
import android.text.style.ParagraphStyle;
import android.text.style.QuoteSpan;
import android.text.style.RelativeSizeSpan;
import android.text.style.URLSpan;
import android.util.LogPrinter;
import android.util.Pair;
import android.util.TypedValue;
import android.view.Gravity;
@ -206,7 +202,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.regex.Pattern;
import javax.activation.DataHandler;
@ -340,8 +335,6 @@ public class FragmentCompose extends FragmentBase {
private static final int REQUEST_SEND = 15;
private static final int REQUEST_REMOVE_ATTACHMENTS = 16;
private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "compose");
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -1399,7 +1392,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(FragmentCompose.this, args, "compose:identity");
}.serial().execute(FragmentCompose.this, args, "compose:identity");
}
private void onReferenceEdit() {
@ -1490,7 +1483,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(FragmentCompose.this, args, "compose:convert");
}.serial().execute(FragmentCompose.this, args, "compose:convert");
}
private void copyRef() {
@ -2007,7 +2000,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(this, args, "compose:encrypt");
}.serial().execute(this, args, "compose:encrypt");
}
private void onMenuZoom() {
@ -2262,7 +2255,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(FragmentCompose.this, args, "compose:answer");
}.serial().execute(FragmentCompose.this, args, "compose:answer");
return true;
}
@ -2275,7 +2268,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(getContext(), getViewLifecycleOwner(), new Bundle(), "compose:answer");
}.serial().execute(getContext(), getViewLifecycleOwner(), new Bundle(), "compose:answer");
}
private void onMenuAnswerCreate() {
@ -2473,7 +2466,7 @@ public class FragmentCompose extends FragmentBase {
etBody.setSelection(paragraph.second);
Log.unexpectedError(getParentFragmentManager(), ex, false);
}
}.setExecutor(executor).execute(FragmentCompose.this, args, "compose:translate");
}.serial().execute(FragmentCompose.this, args, "compose:translate");
}
});
@ -2713,7 +2706,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(this, args, "compose:alias");
}.serial().execute(this, args, "compose:alias");
} else {
try {
List<Address> recipients = new ArrayList<>();
@ -2989,7 +2982,7 @@ public class FragmentCompose extends FragmentBase {
else
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(this, args, "compose:picked");
}.serial().execute(this, args, "compose:picked");
}
@Override
@ -3190,7 +3183,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
handleException(ex);
}
}.setExecutor(executor).execute(this, args, "compose:attachment:add");
}.serial().execute(this, args, "compose:attachment:add");
}
void onSharedAttachments(ArrayList<Uri> uris) {
@ -3639,7 +3632,7 @@ public class FragmentCompose extends FragmentBase {
} else
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(this, args, "compose:pgp");
}.serial().execute(this, args, "compose:pgp");
}
private void onSmime(Bundle args, final int action, final Bundle extras) {
@ -4029,7 +4022,7 @@ public class FragmentCompose extends FragmentBase {
Log.unexpectedError(getParentFragmentManager(), ex, !expected);
}
}
}.setExecutor(executor).execute(this, args, "compose:s/mime");
}.serial().execute(this, args, "compose:s/mime");
}
private void onContactGroupSelected(Bundle args) {
@ -4173,7 +4166,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(this, args, "compose:picked");
}.serial().execute(this, args, "compose:picked");
}
private void onSelectIdentity(Bundle args) {
@ -5773,7 +5766,7 @@ public class FragmentCompose extends FragmentBase {
} else
handleException(ex);
}
}.setExecutor(executor);
}.serial();
private void handleException(Throwable ex) {
// External app sending absolute file
@ -6684,7 +6677,7 @@ public class FragmentCompose extends FragmentBase {
if (ani != null && ani.isConnected())
DnsHelper.checkMx(context, addresses);
}
}.setExecutor(executor);
}.serial();
private String getActionName(int id) {
if (id == R.id.action_delete) {
@ -6934,7 +6927,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(this, args, "compose:show");
}.serial().execute(this, args, "compose:show");
}
private void setFocus(Integer v, int start, int end, boolean restore) {
@ -7616,7 +7609,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(FragmentDialogSend.this, args, "compose:plain_only");
}.serial().execute(FragmentDialogSend.this, args, "compose:plain_only");
}
});
@ -7645,7 +7638,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(FragmentDialogSend.this, args, "compose:receipt");
}.serial().execute(FragmentDialogSend.this, args, "compose:receipt");
}
});
@ -7724,7 +7717,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(FragmentDialogSend.this, args, "compose:encrypt");
}.serial().execute(FragmentDialogSend.this, args, "compose:encrypt");
}
});
@ -7772,7 +7765,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(FragmentDialogSend.this, args, "compose:priority");
}.serial().execute(FragmentDialogSend.this, args, "compose:priority");
}
});
@ -7813,7 +7806,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(FragmentDialogSend.this, args, "compose:sensitivity");
}.serial().execute(FragmentDialogSend.this, args, "compose:sensitivity");
}
});
@ -7985,7 +7978,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
// Ignored
}
}.setExecutor(executor).execute(FragmentDialogSend.this, aargs, "send:archive");
}.serial().execute(FragmentDialogSend.this, aargs, "send:archive");
AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setView(dview)
@ -8042,7 +8035,7 @@ public class FragmentCompose extends FragmentBase {
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(this, args, "compose:snooze");
}.serial().execute(this, args, "compose:snooze");
}
}
}

@ -65,7 +65,6 @@ import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
public class FragmentDialogFolder extends FragmentDialogBase {
private int result = 0;
@ -75,9 +74,6 @@ public class FragmentDialogFolder extends FragmentDialogBase {
private static final int MAX_SELECTED_FOLDERS = 5;
private static final int REQUEST_FOLDER_NAME = 1;
private static final ExecutorService executor =
Helper.getBackgroundExecutor(1, "folder");
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
@ -219,7 +215,7 @@ public class FragmentDialogFolder extends FragmentDialogBase {
final DB db = DB.getInstance(context);
executor.submit(new Runnable() {
Helper.getParallelExecutor().submit(new Runnable() {
@Override
public void run() {
try {
@ -387,7 +383,7 @@ public class FragmentDialogFolder extends FragmentDialogBase {
private static void increaseSelectedCount(Long id, Context context) {
final DB db = DB.getInstance(context);
executor.submit(new Runnable() {
Helper.getParallelExecutor().submit(new Runnable() {
@Override
public void run() {
try {

@ -243,7 +243,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.function.Consumer;
@ -449,8 +448,6 @@ public class FragmentMessages extends FragmentBase
"time", "unread", "starred", "priority"
));
private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "messages");
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -691,9 +688,7 @@ public class FragmentMessages extends FragmentBase
rvMessage.setHasFixedSize(false);
int threads = prefs.getInt("query_threads", DB.DEFAULT_QUERY_THREADS);
if (threads >= 4)
rvMessage.setItemViewCacheSize(ITEM_CACHE_SIZE);
rvMessage.setItemViewCacheSize(ITEM_CACHE_SIZE);
//rvMessage.getRecycledViewPool().setMaxRecycledViews(0, 10); // Default 5
final LinearLayoutManager llm = new LinearLayoutManager(getContext()) {
@ -6351,7 +6346,7 @@ public class FragmentMessages extends FragmentBase
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).setId("messages:" + FragmentMessages.this.hashCode()).execute(this, args, "quickactions");
}.serial().setId("messages:" + FragmentMessages.this.hashCode()).execute(this, args, "quickactions");
} else {
fabMore.hide();
tvSelectedCount.setVisibility(View.GONE);
@ -8519,7 +8514,7 @@ public class FragmentMessages extends FragmentBase
} else
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.setExecutor(executor).execute(this, args, "decrypt:pgp");
}.serial().execute(this, args, "decrypt:pgp");
}
private void onSmime(Bundle args) {
@ -9176,7 +9171,7 @@ public class FragmentMessages extends FragmentBase
}
return trace;
}
}.setExecutor(executor).execute(this, args, "decrypt:s/mime");
}.serial().execute(this, args, "decrypt:s/mime");
}
private static void checkPep(EntityMessage message, List<EntityAttachment> remotes, Context context) {
@ -9759,8 +9754,6 @@ public class FragmentMessages extends FragmentBase
args.putBoolean("print_html_images", print_html_images);
new SimpleTask<String[]>() {
private final ExecutorService executor = Helper.getBackgroundExecutor(0, "print");
@Override
protected String[] onExecute(Context context, Bundle args) throws IOException {
long id = args.getLong("id");
@ -9818,7 +9811,7 @@ public class FragmentMessages extends FragmentBase
continue;
}
futures.add(executor.submit(new Callable<Void>() {
futures.add(Helper.getParallelExecutor().submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
try (OutputStream os = new FileOutputStream(out)) {
@ -10111,7 +10104,7 @@ public class FragmentMessages extends FragmentBase
return;
DB db = DB.getInstance(context);
db.getQueryExecutor().execute(new Runnable() {
Helper.getParallelExecutor().execute(new Runnable() {
@Override
public void run() {
try {

@ -61,7 +61,6 @@ import com.google.android.material.tabs.TabLayout;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
public class FragmentOptions extends FragmentBase {
private ViewPager pager;
@ -69,9 +68,6 @@ public class FragmentOptions extends FragmentBase {
private String searching = null;
private SuggestData data = null;
private final ExecutorService executor =
Helper.getBackgroundExecutor(1, "suggest");
private static final int[] TAB_PAGES = {
R.layout.fragment_setup,
R.layout.fragment_options_synchronize,
@ -386,8 +382,7 @@ public class FragmentOptions extends FragmentBase {
return data;
}
}.setExecutor(executor)
.execute(FragmentOptions.this, args, "option:suggest");
}.serial().execute(FragmentOptions.this, args, "option:suggest");
}
private void _suggest(String query) {

@ -176,9 +176,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
private SwitchCompat swWorkManager;
private SwitchCompat swExternalStorage;
private TextView tvExternalStorageFolder;
private TextView tvRoomQueryThreads;
private SeekBar sbRoomQueryThreads;
private ImageButton ibRoom;
private SwitchCompat swIntegrity;
private SwitchCompat swWal;
private SwitchCompat swCheckpoints;
@ -261,7 +258,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
"watchdog", "experiments", "main_log", "main_log_memory", "protocol", "log_level", "debug", "leak_canary",
"test1", "test2", "test3", "test4", "test5",
"work_manager", // "external_storage",
"query_threads",
"sqlite_integrity_check", "wal", "sqlite_checkpoints", "sqlite_analyze", "sqlite_auto_vacuum", "sqlite_sync_extra", "sqlite_cache",
"chunk_size", "thread_range", "undo_manager",
"browser_zoom", "fake_dark",
@ -393,9 +389,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
swWorkManager = view.findViewById(R.id.swWorkManager);
swExternalStorage = view.findViewById(R.id.swExternalStorage);
tvExternalStorageFolder = view.findViewById(R.id.tvExternalStorageFolder);
tvRoomQueryThreads = view.findViewById(R.id.tvRoomQueryThreads);
sbRoomQueryThreads = view.findViewById(R.id.sbRoomQueryThreads);
ibRoom = view.findViewById(R.id.ibRoom);
swIntegrity = view.findViewById(R.id.swIntegrity);
swWal = view.findViewById(R.id.swWal);
swCheckpoints = view.findViewById(R.id.swCheckpoints);
@ -1245,31 +1238,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
}
});
sbRoomQueryThreads.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
prefs.edit().putInt("query_threads", progress).apply();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
// Do nothing
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
// Do nothing
}
});
ibRoom.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
prefs.edit().remove("debug").commit();
ApplicationEx.restart(v.getContext(), "query_threads");
}
});
swIntegrity.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton v, boolean checked) {
@ -2193,10 +2161,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
swWorkManager.setChecked(prefs.getBoolean("work_manager", true));
swExternalStorage.setChecked(prefs.getBoolean("external_storage", false));
int query_threads = prefs.getInt("query_threads", DB.DEFAULT_QUERY_THREADS);
tvRoomQueryThreads.setText(getString(R.string.title_advanced_room_query_threads, NF.format(query_threads)));
sbRoomQueryThreads.setProgress(query_threads);
swIntegrity.setChecked(prefs.getBoolean("sqlite_integrity_check", true));
swWal.setChecked(prefs.getBoolean("wal", true));
swCheckpoints.setChecked(prefs.getBoolean("sqlite_checkpoints", true));

@ -59,7 +59,6 @@ import androidx.constraintlayout.widget.Group;
import androidx.preference.PreferenceManager;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
public class FragmentOptionsNotifications extends FragmentBase implements SharedPreferences.OnSharedPreferenceChangeListener {
@ -125,9 +124,6 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
private Group grpBackground;
private Group grpTiles;
private static final ExecutorService executor =
Helper.getBackgroundExecutor(1, "notifications");
private final static String[] RESET_OPTIONS = new String[]{
"notify_newest_first", "notify_summary",
"notify_trash", "notify_junk", "notify_block_sender", "notify_archive", "notify_move",
@ -817,7 +813,7 @@ public class FragmentOptionsNotifications extends FragmentBase implements Shared
ComponentName.createRelative(context, cls.getName()),
context.getString(title),
Icon.createWithResource(context, icon),
executor,
Helper.getParallelExecutor(),
new Consumer<Integer>() {
@Override
public void accept(Integer result) {

@ -178,6 +178,7 @@ public class Helper {
static final float LOW_LIGHT = 0.6f;
static final int OPERATION_WORKERS = 3;
static final int WAKELOCK_MAX = 30 * 60 * 1000; // milliseconds
static final int BUFFER_SIZE = 8192; // Same as in Files class
static final long MIN_REQUIRED_SPACE = 100 * 1000L * 1000L;
@ -245,9 +246,40 @@ public class Helper {
"wsc", "wsf", "wsh"
));
private static final ExecutorService executor = getBackgroundExecutor(1, "helper");
static ExecutorService sSerialExecutor = null;
static ExecutorService sParallelExecutor = null;
static ExecutorService sSerialTaskExecutor = null;
static ExecutorService getBackgroundExecutor(int threads, final String name) {
static int sOperationIndex = 0;
static ExecutorService[] sOperationExecutor = new ExecutorService[OPERATION_WORKERS];
static ExecutorService getSerialExecutor() {
if (sSerialExecutor == null)
sSerialExecutor = getBackgroundExecutor(1, "serial");
return sSerialExecutor;
}
static ExecutorService getParallelExecutor() {
if (sParallelExecutor == null)
sParallelExecutor = getBackgroundExecutor(0, "parallel");
return sParallelExecutor;
}
static ExecutorService getSerialTaskExecutor() {
if (sSerialTaskExecutor == null)
sSerialTaskExecutor = getBackgroundExecutor(1, "task");
return sSerialTaskExecutor;
}
static ExecutorService getOperationExecutor() {
if (sOperationExecutor[sOperationIndex] == null)
sOperationExecutor[sOperationIndex] = getBackgroundExecutor(1, "operation");
ExecutorService result = sOperationExecutor[sOperationIndex];
sOperationIndex = (sOperationIndex + 1) % sOperationExecutor.length;
return result;
}
private static ExecutorService getBackgroundExecutor(int threads, final String name) {
ThreadFactory factory = new ThreadFactory() {
private final AtomicInteger threadId = new AtomicInteger();
@ -264,7 +296,7 @@ public class Helper {
// java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
// 1040 KB native stack size / 32 KB thread stack size ~ 32 threads
int processors = Runtime.getRuntime().availableProcessors(); // Modern devices: 8
threads = processors * (BuildConfig.DEBUG ? 8 : 4);
threads = processors * 2;
}
if (threads == 0)
@ -396,9 +428,14 @@ public class Helper {
}
static class PriorityRunnable implements Runnable {
private long group;
private int priority;
private long order;
long getGroup() {
return this.group;
}
int getPriority() {
return this.priority;
}
@ -407,7 +444,8 @@ public class Helper {
return this.order;
}
PriorityRunnable(int priority, long order) {
PriorityRunnable(long group, int priority, long order) {
this.group = group;
this.priority = priority;
this.order = order;
}
@ -2696,7 +2734,7 @@ public class Helper {
? R.string.title_setup_biometrics_disable
: R.string.title_setup_biometrics_enable));
final BiometricPrompt prompt = new BiometricPrompt(activity, executor,
final BiometricPrompt prompt = new BiometricPrompt(activity, Helper.getParallelExecutor(),
new BiometricPrompt.AuthenticationCallback() {
private int fails = 0;

@ -81,11 +81,6 @@ import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
class ImageHelper {
private static final ExecutorService executor_1 =
Helper.getBackgroundExecutor(1, "image_1");
private static final ExecutorService executor_n =
Helper.getBackgroundExecutor(0, "image_n");
static final int DOWNLOAD_TIMEOUT = 15; // seconds
private static final int MAX_PROBE = 128 * 1024; // bytes
private static final int SLOW_CONNECTION = 2 * 1024; // Kbps
@ -475,7 +470,9 @@ class ImageHelper {
lld.setLevel(1);
Integer kbps = ConnectionHelper.getLinkDownstreamBandwidthKbps(context);
ExecutorService executor = (kbps != null && kbps < SLOW_CONNECTION ? executor_1 : executor_n);
ExecutorService executor = (kbps != null && kbps < SLOW_CONNECTION
? Helper.getSerialExecutor()
: Helper.getParallelExecutor());
executor.submit(new Runnable() {
@Override

@ -14,7 +14,6 @@ import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.OnLifecycleEvent;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@ -22,8 +21,6 @@ public class MediaPlayerHelper {
static final int DEFAULT_SOUND_DURATION = 30; // seconds
static final int DEFAULT_ALARM_DURATION = 30; // seconds
private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "media");
static void queue(Context context, String uri) {
try {
queue(context, Uri.parse(uri), false, DEFAULT_SOUND_DURATION);
@ -35,7 +32,7 @@ public class MediaPlayerHelper {
static void queue(Context context, Uri uri, boolean alarm, int duration) {
Log.i("Queuing sound=" + uri);
executor.submit(new Runnable() {
Helper.getSerialExecutor().submit(new Runnable() {
@Override
public void run() {
try {
@ -114,7 +111,7 @@ public class MediaPlayerHelper {
try {
if (owner.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
if (!registered) {
am.addOnModeChangedListener(executor, listener);
am.addOnModeChangedListener(Helper.getParallelExecutor(), listener);
registered = true;
}
} else {

@ -36,7 +36,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
public class ServiceExternal extends Service {
private static final String ACTION_POLL = BuildConfig.APPLICATION_ID + ".POLL";
@ -51,10 +50,6 @@ public class ServiceExternal extends Service {
// adb shell am start-foreground-service -a eu.faircode.email.INTERVAL --ei minutes {0, 15, 30, 60, 120, 240, 480, 1440}
// adb shell am start-foreground-service -a eu.faircode.email.DISCONNECT
private static final ExecutorService executor =
Helper.getBackgroundExecutor(1, "external");
@Override
public void onCreate() {
Log.i("Service external create");
@ -86,7 +81,7 @@ public class ServiceExternal extends Service {
EntityLog.log(this, action);
final Context context = getApplicationContext();
executor.submit(new Runnable() {
Helper.getSerialExecutor().submit(new Runnable() {
@Override
public void run() {
try {

@ -58,7 +58,6 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import javax.mail.Address;
import javax.mail.AuthenticationFailedException;
@ -84,8 +83,6 @@ public class ServiceSend extends ServiceBase implements SharedPreferences.OnShar
private PowerManager.WakeLock wlOutbox;
private List<Long> handling = new ArrayList<>();
private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "send");
private static final int RETRY_MAX = 3;
private static final int CONNECTIVITY_DELAY = 5000; // milliseconds
private static final int PROGRESS_UPDATE_INTERVAL = 1000; // milliseconds
@ -149,7 +146,7 @@ public class ServiceSend extends ServiceBase implements SharedPreferences.OnShar
"Send process=" + TextUtils.join(",", process) +
" handling=" + TextUtils.join(",", handling));
executor.submit(new Runnable() {
Helper.getSerialExecutor().submit(new Runnable() {
@Override
public void run() {
processOperations(process);
@ -900,7 +897,7 @@ public class ServiceSend extends ServiceBase implements SharedPreferences.OnShar
}
static void boot(final Context context) {
executor.submit(new Runnable() {
Helper.getSerialExecutor().submit(new Runnable() {
@Override
public void run() {
try {

@ -128,8 +128,6 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
private final MutableLiveData<List<TupleAccountState>> liveAccountState = new MutableLiveData<>();
private final MediatorState liveAccountNetworkState = new MediatorState();
private static final ExecutorService executor = Helper.getBackgroundExecutor(1, "sync");
private static final long BACKUP_DELAY = 30 * 1000L; // milliseconds
private static final long PURGE_DELAY = 30 * 1000L; // milliseconds
private static final int QUIT_DELAY = 10; // seconds
@ -260,7 +258,6 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
private PowerManager pm = Helper.getSystemService(ServiceSynchronize.this, PowerManager.class);
private PowerManager.WakeLock wl = pm.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, BuildConfig.APPLICATION_ID + ":service");
private ExecutorService queue = Helper.getBackgroundExecutor(1, "service");
@Override
public void onChanged(List<TupleAccountNetworkState> accountNetworkStates) {
@ -467,7 +464,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
}
private void init(final TupleAccountNetworkState accountNetworkState) {
queue.submit(new RunnableEx("state#init") {
Helper.getSerialExecutor().submit(new RunnableEx("state#init") {
@Override
public void delegate() {
long start = new Date().getTime();
@ -526,7 +523,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
}, "sync.account." + accountNetworkState.accountState.id);
coreStates.put(accountNetworkState.accountState.id, astate);
queue.submit(new RunnableEx("state#start") {
Helper.getSerialExecutor().submit(new RunnableEx("state#start") {
@Override
public void delegate() {
long start = new Date().getTime();
@ -567,7 +564,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
EntityLog.log(ServiceSynchronize.this, EntityLog.Type.Scheduling,
"Service stop=" + accountNetworkState);
queue.submit(new RunnableEx("state#stop") {
Helper.getSerialExecutor().submit(new RunnableEx("state#stop") {
@Override
public void delegate() {
long start = new Date().getTime();
@ -605,7 +602,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
EntityLog.log(ServiceSynchronize.this, EntityLog.Type.Scheduling,
"Service delete=" + accountNetworkState);
queue.submit(new RunnableEx("state#delete") {
Helper.getSerialExecutor().submit(new RunnableEx("state#delete") {
@Override
public void delegate() {
long start = new Date().getTime();
@ -632,7 +629,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
}
private void quit(final Integer eventId) {
queue.submit(new RunnableEx("state#quit") {
Helper.getSerialExecutor().submit(new RunnableEx("state#quit") {
@Override
public void delegate() {
long start = new Date().getTime();
@ -691,7 +688,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
private final Runnable backup = new RunnableEx("state#backup") {
@Override
public void delegate() {
queue.submit(new RunnableEx("state#backup#exec") {
Helper.getSerialExecutor().submit(new RunnableEx("state#backup#exec") {
@Override
public void delegate() {
long start = new Date().getTime();
@ -841,12 +838,9 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
});
mutableUnseenNotify.observe(mowner, new Observer<List<TupleMessageEx>>() {
private final ExecutorService executor =
Helper.getBackgroundExecutor(1, "notify");
@Override
public void onChanged(final List<TupleMessageEx> messages) {
executor.submit(new RunnableEx("mutableUnseenNotify") {
Helper.getSerialExecutor().submit(new RunnableEx("mutableUnseenNotify") {
@Override
public void delegate() {
try {
@ -1176,7 +1170,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
String action = intent.getAction();
long id = Long.parseLong(action.split(":")[1]);
executor.submit(new RunnableEx("unsnooze") {
Helper.getSerialExecutor().submit(new RunnableEx("unsnooze") {
@Override
public void delegate() {
try {
@ -1297,7 +1291,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
String action = intent.getAction();
long id = Long.parseLong(action.split(":")[1]);
executor.submit(new RunnableEx("exists") {
Helper.getSerialExecutor().submit(new RunnableEx("exists") {
@Override
public void delegate() {
try {
@ -1333,7 +1327,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
}
private void onPoll(Intent intent) {
executor.submit(new RunnableEx("poll") {
Helper.getSerialExecutor().submit(new RunnableEx("poll") {
@Override
public void delegate() {
try {
@ -1532,8 +1526,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
Log.i(account.name + " run thread=" + currentThread);
final ObjectHolder<TwoStateOwner> cowner = new ObjectHolder<>();
final ExecutorService executor =
Helper.getBackgroundExecutor(1, "account_" + account.id);
final ExecutorService executor = Helper.getOperationExecutor();
// Debug
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
@ -1633,6 +1626,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
}
};
final long group = Thread.currentThread().getId();
final Map<EntityFolder, IMAPFolder> mapFolders = new LinkedHashMap<>();
List<Thread> idlers = new ArrayList<>();
try {
@ -2143,7 +2137,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
crumb.put("serial", Long.toString(serial));
Log.breadcrumb("Queuing", crumb);
executor.submit(new Helper.PriorityRunnable(key.getPriority(), key.getOrder()) {
executor.submit(new Helper.PriorityRunnable(group, key.getPriority(), key.getOrder()) {
@Override
public void run() {
super.run();
@ -2578,6 +2572,11 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
// Stop executing operations
Log.i(account.name + " stop executing operations");
state.nextSerial();
for (Runnable task : ((ThreadPoolExecutor) executor).getQueue().toArray(new Runnable[0]))
if (task instanceof Helper.PriorityRunnable &&
((Helper.PriorityRunnable) task).getGroup() == group)
((ThreadPoolExecutor) executor).remove(task);
((ThreadPoolExecutor) executor).getQueue().clear();
// Close store
@ -3109,7 +3108,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
}
static void boot(final Context context) {
executor.submit(new RunnableEx("boot") {
Helper.getSerialExecutor().submit(new RunnableEx("boot") {
@Override
public void delegate() {
try {
@ -3170,7 +3169,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
AlarmManagerCompatEx.setAndAllowWhileIdle(context, am, AlarmManager.RTC_WAKEUP, next, pi);
}
executor.submit(new RunnableEx("schedule") {
Helper.getSerialExecutor().submit(new RunnableEx("schedule") {
@Override
protected void delegate() {
boolean work = false;

@ -66,7 +66,6 @@ public abstract class SimpleTask<T> implements LifecycleObserver {
private Handler handler = null;
private static PowerManager.WakeLock wl = null;
private static ExecutorService globalExecutor = null;
private static int themeId = -1;
@SuppressLint("StaticFieldLeak")
private static Context themedContext = null;
@ -108,6 +107,10 @@ public abstract class SimpleTask<T> implements LifecycleObserver {
return this;
}
public SimpleTask<T> serial() {
return setExecutor(Helper.getSerialTaskExecutor());
}
@NonNull
public SimpleTask<T> setHandler(Handler handler) {
this.handler = handler;
@ -124,12 +127,7 @@ public abstract class SimpleTask<T> implements LifecycleObserver {
if (localExecutor != null)
return localExecutor;
if (globalExecutor == null) {
int processors = Runtime.getRuntime().availableProcessors();
globalExecutor = Helper.getBackgroundExecutor(processors, "task");
}
return globalExecutor;
return Helper.getParallelExecutor();
}
@NonNull

@ -47,7 +47,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@ -67,9 +66,6 @@ public class TextHelper {
private static final int MAX_CONVERSATION_SAMPLE_SIZE = 8192;
private static final long MAX_CONVERSATION_DURATION = 3000; // milliseconds
private static final ExecutorService executor =
Helper.getBackgroundExecutor(0, "text");
static {
System.loadLibrary("fairemail");
}
@ -192,7 +188,7 @@ public class TextHelper {
.setHints(hints)
.build();
Future<ConversationActions> future = executor.submit(new Callable<ConversationActions>() {
Future<ConversationActions> future = Helper.getParallelExecutor().submit(new Callable<ConversationActions>() {
@Override
@RequiresApi(api = Build.VERSION_CODES.Q)
public ConversationActions call() throws Exception {

@ -44,7 +44,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
public class ViewModelMessages extends ViewModel {
private AdapterMessage.ViewType last = AdapterMessage.ViewType.UNIFIED;
@ -68,9 +67,6 @@ public class ViewModelMessages extends ViewModel {
}
};
// AndroidX IO = 4 threads
private ExecutorService executor = Helper.getBackgroundExecutor(4, "model");
private static final int LOCAL_PAGE_SIZE = 50;
private static final int THREAD_PAGE_SIZE = 100;
private static final int REMOTE_PAGE_SIZE = 10;
@ -204,7 +200,7 @@ public class ViewModelMessages extends ViewModel {
break;
}
builder.setFetchExecutor(executor);
builder.setFetchExecutor(Helper.getParallelExecutor());
model = new Model(args, builder.build(), boundary);
models.put(viewType, model);

@ -38,15 +38,11 @@ import androidx.preference.PreferenceManager;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
public class Widget extends AppWidgetProvider {
private static final ExecutorService executor =
Helper.getBackgroundExecutor(1, "widget");
@Override
public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) {
executor.submit(new Runnable() {
Helper.getParallelExecutor().submit(new Runnable() {
@Override
public void run() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);

@ -1134,50 +1134,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swExternalStorage" />
<TextView
android:id="@+id/tvRoomQueryThreads"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginEnd="48dp"
android:text="@string/title_advanced_room_query_threads"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvExternalStorageFolder" />
<SeekBar
android:id="@+id/sbRoomQueryThreads"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:max="32"
android:min="0"
android:progress="4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvRoomQueryThreads" />
<ImageButton
android:id="@+id/ibRoom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/sbRoomQueryThreads"
app:srcCompat="@drawable/twotone_check_24" />
<TextView
android:id="@+id/tvRoomHint"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="48dp"
android:text="@string/title_advanced_english_hint"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="italic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/ibRoom" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swIntegrity"
android:layout_width="0dp"
@ -1187,7 +1143,7 @@
android:text="@string/title_advanced_integrity"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvRoomHint"
app:layout_constraintTop_toBottomOf="@id/tvExternalStorageFolder"
app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat

@ -795,7 +795,6 @@
<string name="title_advanced_autostart" translatable="false">Autostart app</string>
<string name="title_advanced_work_manager" translatable="false">Initialize work manager</string>
<string name="title_advanced_external_storage" translatable="false">Use external storage</string>
<string name="title_advanced_room_query_threads" translatable="false">ROOM query threads: %1$s</string>
<string name="title_advanced_integrity" translatable="false">sqlite integrity check</string>
<string name="title_advanced_wal" translatable="false">sqlite WAL</string>
<string name="title_advanced_checkpoints" translatable="false">sqlite checkpoints</string>

Loading…
Cancel
Save