FairEmail/app/src/main/java/eu/faircode/email/ApplicationEx.java

1052 lines
44 KiB
Java
Raw Normal View History

2018-08-02 13:33:06 +00:00
package eu.faircode.email;
/*
2018-08-14 05:53:24 +00:00
This file is part of FairEmail.
2018-08-02 13:33:06 +00:00
2018-08-14 05:53:24 +00:00
FairEmail is free software: you can redistribute it and/or modify
2018-08-02 13:33:06 +00:00
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
2018-10-29 10:46:49 +00:00
FairEmail is distributed in the hope that it will be useful,
2018-08-02 13:33:06 +00:00
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
2018-10-29 10:46:49 +00:00
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
2018-08-02 13:33:06 +00:00
2024-01-01 07:50:49 +00:00
Copyright 2018-2024 by Marcel Bokhorst (M66B)
2018-08-02 13:33:06 +00:00
*/
2021-07-28 06:24:39 +00:00
import android.app.Activity;
2018-08-02 13:33:06 +00:00
import android.app.Application;
import android.content.BroadcastReceiver;
2018-12-09 17:49:52 +00:00
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Build;
2021-07-28 06:24:39 +00:00
import android.os.Bundle;
2020-08-23 15:34:14 +00:00
import android.os.Handler;
import android.os.Looper;
import android.os.StrictMode;
2021-07-28 06:24:39 +00:00
import android.os.SystemClock;
import android.os.strictmode.Violation;
2022-02-11 08:36:32 +00:00
import android.text.TextUtils;
2020-04-04 07:19:19 +00:00
import android.util.Printer;
2019-03-13 13:42:33 +00:00
import android.webkit.CookieManager;
2018-08-03 18:07:12 +00:00
2021-05-15 19:24:10 +00:00
import androidx.annotation.NonNull;
2021-07-28 06:24:39 +00:00
import androidx.annotation.Nullable;
2022-06-16 06:33:35 +00:00
import androidx.appcompat.app.AppCompatDelegate;
2023-09-21 06:45:04 +00:00
import androidx.core.content.ContextCompat;
2022-06-16 06:33:35 +00:00
import androidx.core.os.LocaleListCompat;
2021-10-28 09:33:36 +00:00
import androidx.emoji2.text.DefaultEmojiCompatConfig;
import androidx.emoji2.text.EmojiCompat;
import androidx.emoji2.text.FontRequestEmojiCompatConfig;
2023-09-29 11:36:18 +00:00
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.lifecycle.ProcessLifecycleOwner;
import androidx.preference.PreferenceManager;
2021-03-29 19:11:13 +00:00
import androidx.work.WorkManager;
2020-01-23 08:30:08 +00:00
import java.util.Date;
2019-08-12 11:30:33 +00:00
import java.util.HashMap;
2021-10-04 14:43:08 +00:00
import java.util.List;
import java.util.Locale;
2019-08-12 11:30:33 +00:00
import java.util.Map;
2019-05-10 13:44:36 +00:00
2021-01-20 08:20:07 +00:00
public class ApplicationEx extends Application
2022-02-18 19:39:56 +00:00
implements androidx.work.Configuration.Provider, SharedPreferences.OnSharedPreferenceChangeListener {
2018-08-03 18:07:12 +00:00
private Thread.UncaughtExceptionHandler prev = null;
2023-01-11 12:41:54 +00:00
private static final Object lock = new Object();
@Override
protected void attachBaseContext(Context base) {
2023-12-16 20:53:51 +00:00
FairEmailLoggingProvider.setup(base);
2023-12-14 12:38:51 +00:00
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
Log.i("App shutdown" +
" version=" + BuildConfig.VERSION_NAME + BuildConfig.REVISION +
" process=" + android.os.Process.myPid());
}
});
super.attachBaseContext(getLocalizedContext(base));
}
2020-01-23 07:46:38 +00:00
static Context getLocalizedContext(Context context) {
2022-06-16 06:33:35 +00:00
if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && false)
AppCompatDelegate.setApplicationLocales(LocaleListCompat.getEmptyLocaleList());
2020-01-23 07:46:38 +00:00
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
2020-10-05 19:09:13 +00:00
if (prefs.contains("english")) {
boolean english = prefs.getBoolean("english", false);
if (english)
prefs.edit()
.remove("english")
.putString("language", Locale.US.toLanguageTag())
2020-10-21 06:09:24 +00:00
.commit(); // apply won't work here
2020-10-05 19:09:13 +00:00
}
2021-07-19 05:43:02 +00:00
try {
String language = prefs.getString("language", null);
if (language != null) {
if ("de-AT".equals(language) || "de-LI".equals(language))
language = "de-DE";
Locale locale = Locale.forLanguageTag(language);
Log.i("Set language=" + language + " locale=" + locale);
Locale.setDefault(locale);
Configuration config;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
config = new Configuration(context.getResources().getConfiguration());
else
config = new Configuration();
config.setLocale(locale);
return context.createConfigurationContext(config);
}
} catch (Throwable ex) {
Log.e(ex);
2020-10-05 19:09:13 +00:00
}
return context;
2020-01-23 07:46:38 +00:00
}
2022-02-18 19:39:56 +00:00
@NonNull
public androidx.work.Configuration getWorkManagerConfiguration() {
return new androidx.work.Configuration.Builder()
.setMinimumLoggingLevel(android.util.Log.INFO)
.build();
}
2018-08-03 18:07:12 +00:00
@Override
public void onCreate() {
super.onCreate();
2019-05-10 06:53:45 +00:00
2020-01-23 08:30:08 +00:00
long start = new Date().getTime();
2021-02-27 15:00:31 +00:00
Log.i("App create" +
2021-09-28 20:16:03 +00:00
" version=" + BuildConfig.VERSION_NAME + BuildConfig.REVISION +
2021-01-22 16:34:50 +00:00
" process=" + android.os.Process.myPid());
Log.logMemory(this, "App");
2018-08-03 18:07:12 +00:00
2023-12-14 12:48:57 +00:00
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
final boolean crash_reports = prefs.getBoolean("crash_reports", false);
final boolean leak_canary = prefs.getBoolean("leak_canary", false);
final boolean load_emoji = prefs.getBoolean("load_emoji", true);
prev = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(@NonNull Thread thread, @NonNull Throwable ex) {
if (!crash_reports && Log.isOwnFault(ex)) {
Log.e(ex);
if (BuildConfig.BETA_RELEASE ||
!Helper.isPlayStoreInstall())
2023-12-15 11:36:20 +00:00
DebugHelper.writeCrashLog(ApplicationEx.this, ex);
2023-12-14 12:48:57 +00:00
if (prev != null)
prev.uncaughtException(thread, ex);
} else {
Log.w(ex);
System.exit(1);
}
}
});
2023-12-02 11:39:00 +00:00
ConnectionHelper.setupProxy(this);
2022-05-02 11:00:42 +00:00
if (BuildConfig.DEBUG)
UriHelper.test(this);
2022-04-23 20:46:59 +00:00
CoalMine.install(this);
2023-09-29 11:36:18 +00:00
ProcessLifecycleOwner.get().getLifecycle().addObserver(new LifecycleObserver() {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart() {
log(true);
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop() {
log(false);
}
private void log(boolean foreground) {
2023-12-14 12:48:57 +00:00
Log.i("App foreground=" + foreground);
2023-09-29 11:36:18 +00:00
Log.breadcrumb("app", "foreground", Boolean.toString(foreground));
}
});
2021-07-28 06:24:39 +00:00
registerActivityLifecycleCallbacks(lifecycleCallbacks);
2023-12-14 12:48:57 +00:00
if (BuildConfig.DEBUG)
getMainLooper().setMessageLogging(new Printer() {
@Override
public void println(String msg) {
2020-07-26 07:37:03 +00:00
Log.d("Loop: " + msg);
2023-12-14 12:48:57 +00:00
}
});
2020-04-04 07:19:19 +00:00
if (BuildConfig.DEBUG &&
2023-09-08 17:54:17 +00:00
Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && false) {
StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder(StrictMode.getVmPolicy())
.detectNonSdkApiUsage()
.penaltyListener(getMainExecutor(), new StrictMode.OnVmViolationListener() {
@Override
public void onVmViolation(Violation v) {
String message = v.getMessage();
if (message != null &&
(message.contains("AbstractConscryptSocket") ||
message.contains("computeFitSystemWindows") ||
message.contains("makeOptionalFitsSystemWindows")))
return;
StackTraceElement[] stack = v.getStackTrace();
for (StackTraceElement ste : stack) {
String clazz = ste.getClassName();
if (clazz == null)
continue;
if (clazz.startsWith("leakcanary."))
return;
2021-09-02 06:30:05 +00:00
if ("com.sun.mail.util.WriteTimeoutSocket".equals(clazz))
return;
if (clazz.startsWith("org.chromium") ||
clazz.startsWith("com.android.webview.chromium") ||
clazz.startsWith("androidx.appcompat.widget"))
return;
}
Log.e(v);
}
})
.build();
StrictMode.setVmPolicy(policy);
}
2020-04-05 12:10:42 +00:00
Log.setup(this);
2022-04-15 06:18:48 +00:00
CoalMine.setup(leak_canary);
2019-05-10 13:18:53 +00:00
upgrade(this);
2020-11-18 07:25:20 +00:00
try {
boolean tcp_keep_alive = prefs.getBoolean("tcp_keep_alive", false);
2023-09-08 17:54:17 +00:00
if (tcp_keep_alive)
System.setProperty("fairemail.tcp_keep_alive", Boolean.toString(tcp_keep_alive));
else
System.clearProperty("fairemail.tcp_keep_alive");
2020-11-18 07:25:20 +00:00
} catch (Throwable ex) {
Log.e(ex);
}
prefs.registerOnSharedPreferenceChangeListener(this);
2020-10-09 13:22:38 +00:00
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O)
NotificationHelper.createNotificationChannels(this);
2019-05-10 13:18:53 +00:00
2020-04-14 06:32:54 +00:00
DB.setupViewInvalidation(this);
2020-01-23 07:46:38 +00:00
2019-05-10 13:18:53 +00:00
if (Helper.hasWebView(this))
CookieManager.getInstance().setAcceptCookie(false);
2022-09-03 07:24:48 +00:00
// https://issuetracker.google.com/issues/233525229
2021-10-28 09:33:36 +00:00
Log.i("Load emoji=" + load_emoji);
2023-09-21 07:12:39 +00:00
try {
FontRequestEmojiCompatConfig crying = DefaultEmojiCompatConfig.create(this);
if (crying != null) {
crying.setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL);
EmojiCompat.init(crying);
if (load_emoji)
EmojiCompat.get().load();
2021-10-28 09:33:36 +00:00
}
2023-09-21 07:12:39 +00:00
} catch (Throwable ex) {
Log.e(ex);
}
2021-10-28 09:33:36 +00:00
2022-03-22 09:45:02 +00:00
EmailProvider.init(this);
EncryptionHelper.init(this);
2019-07-26 15:57:40 +00:00
MessageHelper.setSystemProperties(this);
2021-01-20 08:20:07 +00:00
2019-07-24 06:52:38 +00:00
ContactInfo.init(this);
2019-06-18 19:20:03 +00:00
2020-07-19 13:50:24 +00:00
DisconnectBlacklist.init(this);
2021-09-24 05:54:50 +00:00
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
2021-09-23 18:06:00 +00:00
ServiceSynchronize.watchdog(this);
ServiceSend.watchdog(this);
}
2020-10-27 07:39:52 +00:00
2022-02-18 19:39:56 +00:00
boolean work_manager = prefs.getBoolean("work_manager", true);
Log.i("Work manager=" + work_manager);
if (work_manager) {
// Legacy
try {
WorkManager.getInstance(this).cancelUniqueWork("WorkerWatchdog");
2023-05-23 06:05:45 +00:00
WorkerAutoUpdate.init(this);
WorkerCleanup.init(this);
WorkerDailyRules.init(this);
WorkerSync.init(this);
2023-11-07 17:29:32 +00:00
} catch (Throwable ex) {
2022-02-18 19:39:56 +00:00
Log.e(ex);
2023-11-07 17:29:32 +00:00
// Exception java.lang.RuntimeException:
// at android.app.ActivityThread.handleBindApplication (ActivityThread.java:6320)
// at android.app.ActivityThread.access$1800 (ActivityThread.java:221)
// at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1860)
// at android.os.Handler.dispatchMessage (Handler.java:102)
// at android.os.Looper.loop (Looper.java:158)
// at android.app.ActivityThread.main (ActivityThread.java:7225)
// at java.lang.reflect.Method.invoke
// at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1230)
// at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1120)
// Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'int java.lang.Object.hashCode()' on a null object reference
// at java.util.Collections.secondaryHash (Collections.java:3427)
// at java.util.HashMap.put (HashMap.java:385)
// at androidx.work.impl.WorkDatabase_Impl.getRequiredTypeConverters (WorkDatabase_Impl.java:312)
// at androidx.room.RoomDatabase.init (RoomDatabase.java:272)
// at androidx.room.RoomDatabase$Builder.build (RoomDatabase.java:1487)
// at androidx.work.impl.WorkDatabase$Companion.create (WorkDatabase.kt:159)
// at androidx.work.impl.WorkDatabase.create (WorkDatabase.kt)
// at androidx.work.impl.WorkManagerImpl.<init> (WorkManagerImpl.java:259)
// at androidx.work.impl.WorkManagerImpl.<init> (WorkManagerImpl.java:234)
// at androidx.work.impl.WorkManagerImpl.initialize (WorkManagerImpl.java:213)
// at androidx.work.impl.WorkManagerImpl.getInstance (WorkManagerImpl.java:168)
// at androidx.work.WorkManager.getInstance (WorkManager.java:184)
// at eu.faircode.email.ApplicationEx.onCreate (ApplicationEx.java:278)
// at android.app.Instrumentation.callApplicationOnCreate (Instrumentation.java:1036)
// at android.app.ActivityThread.handleBindApplication (ActivityThread.java:6317)
2022-02-18 19:39:56 +00:00
}
}
2020-01-22 15:18:21 +00:00
2023-12-06 14:48:55 +00:00
try {
ContextCompat.registerReceiver(this,
onScreenOff,
new IntentFilter(Intent.ACTION_SCREEN_OFF),
ContextCompat.RECEIVER_NOT_EXPORTED);
} catch (Throwable ex) {
Log.e(ex);
/*
Exception java.lang.RuntimeException:
at android.app.ActivityThread.handleBindApplication (ActivityThread.java:7690)
at android.app.ActivityThread.-$$Nest$mhandleBindApplication
at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2478)
at android.os.Handler.dispatchMessage (Handler.java:106)
at android.os.Looper.loopOnce (Looper.java:230)
at android.os.Looper.loop (Looper.java:319)
at android.app.ActivityThread.main (ActivityThread.java:8893)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:608)
at com.android.internal.os.ChildZygoteInit.runZygoteServer (ChildZygoteInit.java:136)
at com.android.internal.os.WebViewZygoteInit.main (WebViewZygoteInit.java:147)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:608)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1103)
Caused by java.lang.SecurityException: Isolated process not allowed to call registerReceiver
at android.os.Parcel.createExceptionOrNull (Parcel.java:3069)
at android.os.Parcel.createException (Parcel.java:3053)
at android.os.Parcel.readException (Parcel.java:3036)
at android.os.Parcel.readException (Parcel.java:2978)
at android.app.IActivityManager$Stub$Proxy.registerReceiverWithFeature (IActivityManager.java:6137)
at android.app.ContextImpl.registerReceiverInternal (ContextImpl.java:1913)
at android.app.ContextImpl.registerReceiver (ContextImpl.java:1860)
at android.content.ContextWrapper.registerReceiver (ContextWrapper.java:791)
at androidx.core.content.ContextCompat$Api33Impl.registerReceiver (ContextCompat.java:1239)
at androidx.core.content.ContextCompat.registerReceiver (ContextCompat.java:870)
at androidx.core.content.ContextCompat.registerReceiver (ContextCompat.java:821)
at eu.faircode.email.ApplicationEx.onCreate (ApplicationEx.java:316)
at android.app.Instrumentation.callApplicationOnCreate (Instrumentation.java:1316)
at android.app.ActivityThread.handleBindApplication (ActivityThread.java:7685)
*/
}
2020-01-23 08:30:08 +00:00
long end = new Date().getTime();
Log.i("App created " + (end - start) + " ms");
2019-05-10 13:18:53 +00:00
}
2020-10-05 19:09:13 +00:00
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
2022-03-23 07:32:47 +00:00
try {
switch (key) {
case "enabled":
ServiceSynchronize.reschedule(this);
WorkerCleanup.init(this);
ServiceSynchronize.scheduleWatchdog(this);
WidgetSync.update(this);
break;
case "poll_interval":
case "schedule":
case "schedule_start":
case "schedule_end":
2023-03-12 09:15:38 +00:00
case "schedule_start_weekend":
case "schedule_end_weekend":
case "weekend":
2022-03-23 07:32:47 +00:00
case "schedule_day0":
case "schedule_day1":
case "schedule_day2":
case "schedule_day3":
case "schedule_day4":
case "schedule_day5":
case "schedule_day6":
ServiceSynchronize.reschedule(this);
break;
case "check_blocklist":
case "use_blocklist":
DnsBlockList.clearCache();
break;
case "watchdog":
ServiceSynchronize.scheduleWatchdog(this);
break;
case "secure": // privacy
case "load_emoji": // privacy
case "shortcuts": // misc
case "language": // misc
case "wal": // misc
// Should be excluded for import
2022-08-08 19:34:19 +00:00
restart(this, key);
2022-03-23 07:32:47 +00:00
break;
2023-12-16 20:53:51 +00:00
case "debug":
case "log_level":
2023-12-30 16:14:02 +00:00
Log.setLevel(this);
2023-12-16 20:53:51 +00:00
FairEmailLoggingProvider.setLevel(this);
break;
2022-03-23 07:32:47 +00:00
}
} catch (Throwable ex) {
Log.e(ex);
2020-10-25 17:21:20 +00:00
}
2020-10-05 19:09:13 +00:00
}
2022-08-08 19:34:19 +00:00
static void restart(Context context, String reason) {
Log.i("Restart because " + reason);
Intent intent = new Intent(context, ActivityMain.class);
2020-10-05 19:09:13 +00:00
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intent);
2020-10-05 19:09:13 +00:00
Runtime.getRuntime().exit(0);
}
2019-05-10 13:18:53 +00:00
@Override
public void onTrimMemory(int level) {
2023-04-17 16:24:27 +00:00
try {
/*
java.lang.NoClassDefFoundError: Not a primitive type: '\u0000'
at androidx.core.content.ContextCompat$Api23Impl.getSystemService(Unknown Source:0)
at androidx.core.content.ContextCompat.getSystemService(SourceFile:7)
at eu.faircode.email.Helper.getSystemService(Unknown Source:4)
at eu.faircode.email.Log.logMemory(SourceFile:8)
at eu.faircode.email.ApplicationEx.onTrimMemory(SourceFile:18)
at android.app.ActivityThread.handleTrimMemory(ActivityThread.java:5453)
*/
Log.logMemory(this, "Trim memory level=" + level);
Map<String, String> crumb = new HashMap<>();
crumb.put("level", Integer.toString(level));
Log.breadcrumb("trim", crumb);
super.onTrimMemory(level);
} catch (Throwable ex) {
Log.e(ex);
}
2019-05-10 13:18:53 +00:00
}
@Override
public void onLowMemory() {
2023-04-17 16:24:27 +00:00
try {
Log.logMemory(this, "Low memory");
Map<String, String> crumb = new HashMap<>();
crumb.put("free", Integer.toString(Log.getFreeMemMb()));
Log.breadcrumb("low", crumb);
2020-09-27 08:42:12 +00:00
2023-04-17 16:24:27 +00:00
ContactInfo.clearCache(this, false);
2020-09-27 08:42:12 +00:00
2023-04-17 16:24:27 +00:00
super.onLowMemory();
} catch (Throwable ex) {
Log.e(ex);
}
2019-05-10 13:18:53 +00:00
}
static void upgrade(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
int version = prefs.getInt("version", BuildConfig.VERSION_CODE);
if (version != BuildConfig.VERSION_CODE)
2020-08-26 08:25:50 +00:00
EntityLog.log(context, "Upgrading from " + version + " to " + BuildConfig.VERSION_CODE);
SharedPreferences.Editor editor = prefs.edit();
2019-07-22 10:31:30 +00:00
2020-08-28 06:54:11 +00:00
if (version < BuildConfig.VERSION_CODE)
editor.remove("crash_report_count");
2022-01-02 15:08:35 +00:00
if (!BuildConfig.TEST_RELEASE)
2022-01-02 17:36:46 +00:00
editor.remove("test1").remove("test2").remove("test3").remove("test4").remove("test5");
2022-01-02 15:08:35 +00:00
2019-05-21 12:28:38 +00:00
if (version < 468) {
editor.remove("notify_trash");
editor.remove("notify_archive");
editor.remove("notify_reply");
editor.remove("notify_flag");
editor.remove("notify_seen");
2019-07-22 10:31:30 +00:00
} else if (version < 601) {
editor.putBoolean("contact_images", prefs.getBoolean("autoimages", true));
editor.remove("autoimages");
} else if (version < 612) {
if (prefs.getBoolean("autonext", false))
editor.putString("onclose", "next");
editor.remove("autonext");
2019-09-09 07:31:55 +00:00
2019-09-07 15:53:06 +00:00
} else if (version < 693) {
editor.remove("message_swipe");
editor.remove("message_select");
2019-09-09 07:31:55 +00:00
} else if (version < 696) {
String theme = prefs.getString("theme", "light");
if ("grey".equals(theme))
editor.putString("theme", "grey_dark");
2019-09-09 07:46:54 +00:00
if (prefs.contains("ascending")) {
editor.putBoolean("ascending_list", prefs.getBoolean("ascending", false));
editor.remove("ascending");
}
} else if (version < 701) {
if (prefs.getBoolean("suggest_local", false)) {
editor.putBoolean("suggest_sent", true);
editor.remove("suggest_local");
}
2019-09-13 09:00:31 +00:00
} else if (version < 703) {
if (!prefs.getBoolean("style_toolbar", true)) {
editor.putBoolean("compose_media", false);
editor.remove("style_toolbar");
}
2019-09-17 09:31:28 +00:00
} else if (version < 709) {
if (prefs.getBoolean("swipe_reversed", false)) {
editor.putBoolean("reversed", true);
editor.remove("swipe_reversed");
}
2019-07-02 08:32:06 +00:00
} else if (version < 741)
editor.remove("send_dialog");
2019-10-06 19:01:01 +00:00
else if (version < 751) {
if (prefs.contains("notify_snooze_duration")) {
int minutes = prefs.getInt("notify_snooze_duration", 60);
int hours = (int) Math.ceil(minutes / 60.0);
editor.putInt("default_snooze", hours);
editor.remove("notify_snooze_duration");
}
2019-11-15 13:27:28 +00:00
} else if (version < 819) {
if (prefs.contains("no_history")) {
editor.putBoolean("secure", prefs.getBoolean("no_history", false));
editor.remove("no_history");
}
2019-11-15 15:08:03 +00:00
if (prefs.contains("zoom")) {
int zoom = prefs.getInt("zoom", 1);
editor.putInt("view_zoom", zoom);
editor.putInt("compose_zoom", zoom);
editor.remove("zoom");
}
2019-12-12 16:51:39 +00:00
} else if (version < 844) {
if (prefs.getBoolean("schedule", false))
editor.putBoolean("enabled", true);
} else if (version < 874) {
if (prefs.contains("experiments") &&
prefs.getBoolean("experiments", false))
editor.putBoolean("quick_filter", true);
editor.remove("experiments");
} else if (version < 889) {
if (prefs.contains("autoresize")) {
boolean autoresize = prefs.getBoolean("autoresize", true);
editor.putBoolean("resize_images", autoresize);
editor.putBoolean("resize_attachments", autoresize);
editor.remove("autoresize");
}
2020-01-28 11:43:56 +00:00
} else if (version < 930) {
boolean large = context.getResources().getConfiguration()
.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);
editor.putBoolean("landscape3", large);
} else if (version < 949) {
if (prefs.contains("automove")) {
boolean automove = prefs.getBoolean("automove", false);
editor.putBoolean("move_1_confirmed", automove);
editor.remove("automove");
}
2020-02-16 12:29:19 +00:00
} else if (version < 972) {
if (prefs.contains("signature_end")) {
boolean signature_end = prefs.getBoolean("signature_end", false);
if (signature_end)
editor.putInt("signature_location", 2);
editor.remove("signature_end");
}
2020-02-23 17:39:42 +00:00
} else if (version < 978) {
if (!prefs.contains("poll_interval"))
editor.putInt("poll_interval", 0);
2020-02-23 18:16:50 +00:00
editor.remove("first");
} else if (version < 1021) {
boolean highlight_unread = prefs.getBoolean("highlight_unread", false);
if (!highlight_unread)
2020-03-20 07:25:01 +00:00
editor.putBoolean("highlight_unread", highlight_unread);
} else if (version < 1121) {
if (!Helper.isPlayStoreInstall())
editor.putBoolean("experiments", true);
2020-04-27 15:50:58 +00:00
} else if (version < 1124) {
editor.remove("experiments");
} else if (version < 1181) {
2020-10-16 11:02:32 +00:00
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
editor.remove("background_service");
} else if (version < 1195)
editor.remove("auto_optimize");
else if (version < 1229) {
boolean monospaced = prefs.getBoolean("monospaced", false);
if (monospaced && !BuildConfig.DEBUG)
editor.putBoolean("text_font", false);
2020-07-04 07:26:11 +00:00
} else if (version < 1238) {
if (!prefs.contains("subject_ellipsize"))
editor.putString("subject_ellipsize", "middle");
2020-07-04 19:01:04 +00:00
if (!prefs.contains("auto_optimize"))
editor.putBoolean("auto_optimize", false);
} else if (version < 1253) {
int threads = prefs.getInt("query_threads", 4);
if (threads == 4)
editor.remove("query_threads");
2020-07-22 06:26:05 +00:00
} else if (version < 1264) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N ||
"Blackview".equalsIgnoreCase(Build.MANUFACTURER) ||
"OnePlus".equalsIgnoreCase(Build.MANUFACTURER) ||
"HUAWEI".equalsIgnoreCase(Build.MANUFACTURER))
editor.putInt("query_threads", 2);
2020-07-28 15:23:07 +00:00
} else if (version < 1274)
ContactInfo.clearCache(context); // Favicon background
2020-09-25 08:19:15 +00:00
else if (version < 1336) {
if (!prefs.contains("beige"))
editor.putBoolean("beige", false);
2020-11-13 19:48:43 +00:00
} else if (version < 1385)
2020-11-09 17:24:50 +00:00
editor.remove("parse_classes");
2020-11-18 07:25:20 +00:00
else if (version < 1401)
editor.remove("tcp_keep_alive");
2020-11-22 10:34:49 +00:00
else if (version < 1407)
editor.remove("print_html_confirmed");
2020-12-02 13:39:48 +00:00
else if (version < 1413)
editor.remove("experiments");
else if (version < 1439) {
2021-01-03 11:41:16 +00:00
if (!BuildConfig.DEBUG)
editor.remove("experiments");
2021-01-18 10:09:53 +00:00
} else if (version < 1461) {
if (!prefs.contains("theme"))
editor.putString("theme", "blue_orange_light");
2021-01-20 13:03:14 +00:00
} else if (version < 1463) {
if (!prefs.contains("autoscroll"))
editor.putBoolean("autoscroll", true);
2021-02-01 10:23:42 +00:00
} else if (version < 1477) {
if (!BuildConfig.DEBUG)
editor.remove("experiments");
} else if (version < 1524) {
if (BuildConfig.PLAY_STORE_RELEASE)
editor.remove("experiments");
} else if (version < 1525) {
if (!prefs.contains("download"))
editor.putInt("download", 512 * 1024);
2021-03-18 10:33:59 +00:00
} else if (version < 1533) {
if (!prefs.contains("biometrics_notify"))
editor.putBoolean("biometrics_notify", false);
2021-03-21 06:52:32 +00:00
} else if (version < 1535) {
editor.remove("identities_asked");
editor.remove("identities_primary_hint");
2021-03-25 16:08:25 +00:00
} else if (version < 1539) {
if (!prefs.contains("double_back"))
editor.putBoolean("double_back", true);
2021-03-28 19:28:46 +00:00
} else if (version < 1540) {
Map<String, ?> all = prefs.getAll();
for (String key : all.keySet())
if (key.startsWith("widget.") && key.endsWith(".semi")) {
String[] k = key.split("\\.");
if (k.length == 3)
try {
int appWidgetId = Integer.parseInt(k[1]);
editor.remove("widget." + appWidgetId + ".background");
} catch (Throwable ex) {
Log.e(ex);
}
}
2021-04-17 09:04:04 +00:00
} else if (version < 1556) {
if (prefs.contains("last_search")) {
editor.putString("last_search1", prefs.getString("last_search", null));
editor.remove("last_search");
}
2021-04-17 12:14:24 +00:00
} else if (version < 1558) {
if (!prefs.contains("button_extra"))
editor.putBoolean("button_extra", true);
2021-05-19 16:15:48 +00:00
} else if (version < 1598) {
if (prefs.contains("deepl")) {
String key = prefs.getString("deepl", null);
editor.putString("deepl_key", key).remove("deepl");
}
2021-06-28 08:10:44 +00:00
} else if (version < 1630) {
boolean experiments = prefs.getBoolean("experiments", false);
if (experiments)
editor.putBoolean("deepl_enabled", true);
2021-08-10 07:23:05 +00:00
} else if (version < 1678) {
Configuration config = context.getResources().getConfiguration();
boolean normal = config.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_NORMAL);
if (!normal) {
if (!prefs.contains("landscape"))
editor.putBoolean("landscape", false);
if (!prefs.contains("landscape3"))
editor.putBoolean("landscape3", false);
}
2021-09-13 05:19:54 +00:00
} else if (version < 1721) {
if (!prefs.contains("discard_delete"))
editor.putBoolean("discard_delete", false);
2021-10-04 14:43:08 +00:00
} else if (version < 1753)
repairFolders(context);
else if (version < 1772)
editor.remove("conversation_actions");
2021-11-22 07:57:17 +00:00
else if (version < 1781) {
2021-11-22 11:53:53 +00:00
if (prefs.contains("sort")) {
String sort = prefs.getString("sort", "time");
editor.putString("sort_unified", sort);
}
2021-11-22 07:57:17 +00:00
if (prefs.contains("ascending_list")) {
boolean ascending = prefs.getBoolean("ascending_list", false);
editor.putBoolean("ascending_unified", ascending);
}
2022-02-11 08:36:32 +00:00
} else if (version < 1835) {
boolean monospaced = prefs.getBoolean("monospaced", false);
String compose_font = prefs.getString("compose_font", "");
if (TextUtils.isEmpty(compose_font))
editor.putString("compose_font", monospaced ? "monospace" : "sans-serif");
if (monospaced) {
String display_font = prefs.getString("display_font", "");
if (TextUtils.isEmpty(display_font))
editor.putString("display_font", "monospace");
}
editor.remove("monospaced");
2022-02-13 21:16:39 +00:00
} else if (version < 1837) {
if (!prefs.contains("compact_folders"))
editor.putBoolean("compact_folders", false);
2022-02-15 19:05:02 +00:00
} else if (version < 1839) {
boolean reply_all = prefs.getBoolean("reply_all", false);
if (reply_all)
editor.remove("reply_all").putString("answer_action", "reply_all");
2022-02-24 18:27:34 +00:00
} else if (version < 1847) {
if (Helper.isAccessibilityEnabled(context))
editor.putBoolean("send_chips", false);
2022-03-11 19:01:49 +00:00
} else if (version < 1855) {
if (!prefs.contains("preview_lines"))
editor.putInt("preview_lines", 2);
2022-04-09 19:25:00 +00:00
} else if (version < 1874) {
boolean cards = prefs.getBoolean("cards", true);
if (!cards)
editor.remove("view_padding");
2022-04-30 09:35:09 +00:00
} else if (version < 1888) {
int class_min_difference = prefs.getInt("class_min_difference", 50);
if (class_min_difference == 0)
editor.putBoolean("classification", false);
2022-06-15 13:36:29 +00:00
} else if (version < 1918) {
2022-06-15 15:38:20 +00:00
if (prefs.contains("browse_links")) {
boolean browse_links = prefs.getBoolean("browse_links", false);
editor.remove("browse_links")
.putBoolean("open_with_tabs", !browse_links);
}
2022-06-24 07:36:54 +00:00
} else if (version < 1927) {
if (!prefs.contains("auto_identity"))
editor.putBoolean("auto_identity", true);
2022-07-05 17:09:18 +00:00
} else if (version < 1931)
editor.remove("button_force_light").remove("fake_dark");
2022-07-11 09:35:53 +00:00
else if (version < 1933) {
2022-12-21 17:20:03 +00:00
editor.putBoolean("lt_enabled", false);
2022-07-11 09:35:53 +00:00
if (prefs.contains("disable_top")) {
editor.putBoolean("use_top", !prefs.getBoolean("disable_top", false));
editor.remove("disable_top");
}
2022-08-08 20:37:13 +00:00
} else if (version < 1947)
editor.putBoolean("accept_unsupported", true);
2022-08-14 05:51:50 +00:00
else if (version < 1951) {
if (prefs.contains("open_unsafe"))
editor.putBoolean("open_safe", !prefs.getBoolean("open_unsafe", true));
2022-08-18 05:48:51 +00:00
} else if (version < 1955) {
if (!prefs.contains("doubletap"))
editor.putBoolean("doubletap", true);
2022-08-31 07:09:42 +00:00
} else if (version < 1960)
editor.remove("sqlite_auto_vacuum");
else if (version < 1961) {
if (!prefs.contains("photo_picker"))
editor.putBoolean("photo_picker", true);
2022-09-14 06:24:46 +00:00
} else if (version < 1966)
editor.remove("hide_timezone");
2022-10-28 14:00:39 +00:00
else if (version < 1994) {
// 2022-10-28 Spamcop blocks Google's addresses
editor.putBoolean("blocklist.Spamcop", false);
2022-12-07 12:31:22 +00:00
} else if (version < 2013) {
if (prefs.contains("compose_block")) {
if (prefs.getBoolean("experiments", false))
editor.putBoolean("compose_style", prefs.getBoolean("compose_block", false));
editor.remove("compose_block");
}
2022-12-18 21:00:00 +00:00
} else if (version < 2016) {
if (!prefs.contains("reset_snooze"))
editor.putBoolean("reset_snooze", false);
} else if (version < 2029) {
if (!prefs.contains("plain_only_reply"))
editor.putBoolean("plain_only_reply", true);
2023-02-20 10:01:01 +00:00
} else if (version < 2046)
editor.remove("message_junk");
2023-05-05 20:56:45 +00:00
else if (version < 2069) {
if (prefs.contains("swipe_sensitivity") && !prefs.contains("swipe_sensitivity_updated")) {
int swipe_sensitivity = prefs.getInt("swipe_sensitivity", FragmentOptionsBehavior.DEFAULT_SWIPE_SENSITIVITY);
if (swipe_sensitivity > 0) {
swipe_sensitivity--;
if (swipe_sensitivity == FragmentOptionsBehavior.DEFAULT_SWIPE_SENSITIVITY)
editor.remove("swipe_sensitivity");
else
editor.putInt("swipe_sensitivity", swipe_sensitivity - 1)
.putBoolean("swipe_sensitivity_updated", true);
}
}
2023-06-04 06:26:06 +00:00
} else if (version < 2075) {
for (String name : new String[]{"seen", "unflagged", "unknown", "snoozed", "deleted"})
if (prefs.contains("filter_" + name))
for (String _type : new String[]{EntityFolder.ARCHIVE, EntityFolder.TRASH, EntityFolder.JUNK}) {
String type = _type.toLowerCase(Locale.ROOT);
if (!prefs.contains("filter_" + type + "_" + name))
editor.putBoolean("filter_" + type + "_" + name, prefs.getBoolean("filter_" + name, false));
}
2023-07-12 06:31:04 +00:00
} else if (version < 2084) {
boolean thread_sent_trash = prefs.getBoolean("thread_sent_trash", false);
if (thread_sent_trash)
editor.putBoolean("move_thread_sent", true);
editor.remove("thread_sent_trash");
2023-07-14 13:26:04 +00:00
} else if (version < 2086) {
boolean override_width = prefs.getBoolean("override_width", false);
if (override_width)
editor.putBoolean("overview_mode", true);
editor.remove("override_width");
2023-08-21 06:23:30 +00:00
} else if (version < 2089) {
2023-07-30 05:25:32 +00:00
if (!prefs.contains("auto_hide_answer"))
editor.putBoolean("auto_hide_answer", !Helper.isAccessibilityEnabled(context));
2023-10-13 06:05:42 +00:00
} else if (version < 2108) {
if (!prefs.getBoolean("updown", false))
editor.putBoolean("updown", false);
2023-10-19 18:41:41 +00:00
} else if (version < 2113)
editor.remove("send_more");
2023-12-08 07:33:15 +00:00
else if (version < 2137) {
// https://support.google.com/faqs/answer/6346016
if (!prefs.contains("cert_strict"))
editor.putBoolean("cert_strict", !BuildConfig.PLAY_STORE_RELEASE);
}
2019-10-06 19:01:01 +00:00
2020-10-16 11:02:32 +00:00
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !BuildConfig.DEBUG)
editor.remove("background_service");
2019-12-22 07:47:32 +00:00
if (version < BuildConfig.VERSION_CODE)
editor.putInt("previous_version", version);
2019-07-22 10:31:30 +00:00
editor.putInt("version", BuildConfig.VERSION_CODE);
editor.apply();
}
2021-10-04 14:43:08 +00:00
static void repairFolders(Context context) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Log.i("Repair folders");
DB db = DB.getInstance(context);
List<EntityAccount> accounts = db.account().getAccounts();
if (accounts == null)
return;
for (EntityAccount account : accounts) {
if (account.protocol != EntityAccount.TYPE_IMAP)
continue;
EntityFolder inbox = db.folder().getFolderByType(account.id, EntityFolder.INBOX);
if (inbox == null || !inbox.synchronize) {
List<EntityFolder> folders = db.folder().getFolders(account.id, false, false);
if (folders == null)
continue;
for (EntityFolder folder : folders) {
if (inbox == null && "inbox".equalsIgnoreCase(folder.name))
folder.type = EntityFolder.INBOX;
2021-10-04 17:45:05 +00:00
if (!folder.local &&
!EntityFolder.USER.equals(folder.type) &&
2021-10-04 14:43:08 +00:00
!EntityFolder.SYSTEM.equals(folder.type)) {
EntityLog.log(context, "Repairing " + account.name + ":" + folder.type);
folder.setProperties();
folder.setSpecials(account);
db.folder().updateFolder(folder);
}
}
}
}
} catch (Throwable ex) {
Log.e(ex);
}
}
}).start();
}
2021-07-28 06:24:39 +00:00
private final ActivityLifecycleCallbacks lifecycleCallbacks = new ActivityLifecycleCallbacks() {
private long last = 0;
@Override
public void onActivityPreCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
log(activity, "onActivityPreCreated");
}
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
log(activity, "onActivityCreated");
}
@Override
public void onActivityPostCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
log(activity, "onActivityPostCreated");
}
@Override
public void onActivityPreStarted(@NonNull Activity activity) {
log(activity, "onActivityPreStarted");
}
@Override
public void onActivityStarted(@NonNull Activity activity) {
log(activity, "onActivityStarted");
}
@Override
public void onActivityPostStarted(@NonNull Activity activity) {
log(activity, "onActivityPostStarted");
}
@Override
public void onActivityPreResumed(@NonNull Activity activity) {
log(activity, "onActivityPreResumed");
}
@Override
public void onActivityResumed(@NonNull Activity activity) {
log(activity, "onActivityResumed");
}
@Override
public void onActivityPostResumed(@NonNull Activity activity) {
log(activity, "onActivityPostResumed");
2023-01-18 14:58:05 +00:00
if (activity instanceof ActivityView ||
(BuildConfig.DEBUG && activity instanceof ActivityCompose))
2022-11-24 09:06:53 +00:00
ServiceSynchronize.state(activity, true);
2021-07-28 06:24:39 +00:00
}
@Override
public void onActivityPrePaused(@NonNull Activity activity) {
log(activity, "onActivityPrePaused");
2023-01-18 14:58:05 +00:00
if (activity instanceof ActivityView ||
(BuildConfig.DEBUG && activity instanceof ActivityCompose))
2022-11-24 09:06:53 +00:00
ServiceSynchronize.state(activity, false);
2021-07-28 06:24:39 +00:00
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
log(activity, "onActivityPaused");
}
@Override
public void onActivityPostPaused(@NonNull Activity activity) {
log(activity, "onActivityPostPaused");
}
@Override
public void onActivityPreStopped(@NonNull Activity activity) {
log(activity, "onActivityPreStopped");
}
@Override
public void onActivityStopped(@NonNull Activity activity) {
log(activity, "onActivityStopped");
}
@Override
public void onActivityPostStopped(@NonNull Activity activity) {
log(activity, "onActivityPostStopped");
}
@Override
public void onActivityPreSaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
log(activity, "onActivityPreSaveInstanceState");
}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
log(activity, "onActivitySaveInstanceState");
}
@Override
public void onActivityPostSaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
log(activity, "onActivityPostSaveInstanceState");
}
@Override
public void onActivityPreDestroyed(@NonNull Activity activity) {
log(activity, "onActivityPreDestroyed");
}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
log(activity, "onActivityDestroyed");
2022-04-15 19:29:00 +00:00
Helper.clearViews(activity);
2021-07-28 06:24:39 +00:00
}
@Override
public void onActivityPostDestroyed(@NonNull Activity activity) {
log(activity, "onActivityPostDestroyed");
}
private void log(@NonNull Activity activity, @NonNull String what) {
long start = last;
last = SystemClock.elapsedRealtime();
long elapsed = (start == 0 ? 0 : last - start);
Log.i(activity.getClass().getSimpleName() + " " + what + " " + elapsed + " ms");
}
};
2021-03-18 10:42:25 +00:00
private final BroadcastReceiver onScreenOff = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("Received " + intent);
Log.logExtras(intent);
2021-10-16 05:50:13 +00:00
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean autolock = prefs.getBoolean("autolock", true);
if (autolock)
Helper.clearAuthentication(ApplicationEx.this);
}
};
2020-08-23 15:34:14 +00:00
private static Handler handler = null;
synchronized static Handler getMainHandler() {
if (handler == null)
2023-01-11 12:41:54 +00:00
synchronized (lock) {
handler = new Handler(Looper.getMainLooper());
}
2020-08-23 15:34:14 +00:00
return handler;
}
2018-08-02 13:33:06 +00:00
}