mirror of
https://github.com/deltachat/deltachat-android.git
synced 2025-10-06 03:49:58 +02:00
238 lines
9.4 KiB
Java
238 lines
9.4 KiB
Java
package org.thoughtcrime.securesms;
|
|
|
|
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_VERIFIED_ONE_ON_ONE_CHATS;
|
|
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.net.ConnectivityManager;
|
|
import android.net.LinkProperties;
|
|
import android.net.NetworkCapabilities;
|
|
import android.os.Build;
|
|
import android.util.Log;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.appcompat.app.AppCompatDelegate;
|
|
import androidx.multidex.MultiDexApplication;
|
|
import androidx.work.Constraints;
|
|
import androidx.work.ExistingPeriodicWorkPolicy;
|
|
import androidx.work.NetworkType;
|
|
import androidx.work.PeriodicWorkRequest;
|
|
import androidx.work.WorkManager;
|
|
|
|
import com.b44t.messenger.DcAccounts;
|
|
import com.b44t.messenger.DcContext;
|
|
import com.b44t.messenger.DcEvent;
|
|
import com.b44t.messenger.DcEventEmitter;
|
|
import com.b44t.messenger.rpc.Rpc;
|
|
import com.b44t.messenger.rpc.RpcException;
|
|
|
|
import org.thoughtcrime.securesms.connect.AccountManager;
|
|
import org.thoughtcrime.securesms.connect.DcEventCenter;
|
|
import org.thoughtcrime.securesms.connect.DcHelper;
|
|
import org.thoughtcrime.securesms.connect.FetchWorker;
|
|
import org.thoughtcrime.securesms.connect.ForegroundDetector;
|
|
import org.thoughtcrime.securesms.connect.KeepAliveService;
|
|
import org.thoughtcrime.securesms.connect.NetworkStateReceiver;
|
|
import org.thoughtcrime.securesms.crypto.DatabaseSecret;
|
|
import org.thoughtcrime.securesms.crypto.DatabaseSecretProvider;
|
|
import org.thoughtcrime.securesms.geolocation.DcLocationManager;
|
|
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
|
import org.thoughtcrime.securesms.notifications.FcmReceiveService;
|
|
import org.thoughtcrime.securesms.notifications.InChatSounds;
|
|
import org.thoughtcrime.securesms.notifications.NotificationCenter;
|
|
import org.thoughtcrime.securesms.util.AndroidSignalProtocolLogger;
|
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
|
import org.thoughtcrime.securesms.util.Prefs;
|
|
import org.thoughtcrime.securesms.util.SignalProtocolLoggerProvider;
|
|
import org.thoughtcrime.securesms.util.Util;
|
|
|
|
import java.io.File;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
public class ApplicationContext extends MultiDexApplication {
|
|
private static final String TAG = ApplicationContext.class.getSimpleName();
|
|
|
|
public static DcAccounts dcAccounts;
|
|
public Rpc rpc;
|
|
public DcContext dcContext;
|
|
public DcLocationManager dcLocationManager;
|
|
public DcEventCenter eventCenter;
|
|
public NotificationCenter notificationCenter;
|
|
private JobManager jobManager;
|
|
|
|
private int debugOnAvailableCount;
|
|
private int debugOnBlockedStatusChangedCount;
|
|
private int debugOnCapabilitiesChangedCount;
|
|
private int debugOnLinkPropertiesChangedCount;
|
|
|
|
public static ApplicationContext getInstance(@NonNull Context context) {
|
|
return (ApplicationContext)context.getApplicationContext();
|
|
}
|
|
|
|
@Override
|
|
public void onCreate() {
|
|
super.onCreate();
|
|
|
|
// if (LeakCanary.isInAnalyzerProcess(this)) {
|
|
// // This process is dedicated to LeakCanary for heap analysis.
|
|
// // You should not init your app in this process.
|
|
// return;
|
|
// }
|
|
// LeakCanary.install(this);
|
|
|
|
Log.i("DeltaChat", "++++++++++++++++++ ApplicationContext.onCreate() ++++++++++++++++++");
|
|
|
|
System.loadLibrary("native-utils");
|
|
|
|
dcAccounts = new DcAccounts(new File(getFilesDir(), "accounts").getAbsolutePath());
|
|
rpc = new Rpc(dcAccounts.getJsonrpcInstance());
|
|
rpc.start();
|
|
AccountManager.getInstance().migrateToDcAccounts(this);
|
|
int[] allAccounts = dcAccounts.getAll();
|
|
for (int accountId : allAccounts) {
|
|
DcContext ac = dcAccounts.getAccount(accountId);
|
|
if (!ac.isOpen()) {
|
|
try {
|
|
DatabaseSecret secret = DatabaseSecretProvider.getOrCreateDatabaseSecret(this, accountId);
|
|
boolean res = ac.open(secret.asString());
|
|
if (res) Log.i(TAG, "Successfully opened account " + accountId + ", path: " + ac.getBlobdir());
|
|
else Log.e(TAG, "Error opening account " + accountId + ", path: " + ac.getBlobdir());
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "Failed to open account " + accountId + ", path: " + ac.getBlobdir() + ": " + e);
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
if (allAccounts.length == 0) {
|
|
try {
|
|
rpc.addAccount();
|
|
} catch (RpcException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
dcContext = dcAccounts.getSelectedAccount();
|
|
notificationCenter = new NotificationCenter(this);
|
|
eventCenter = new DcEventCenter(this);
|
|
new Thread(() -> {
|
|
DcEventEmitter emitter = dcAccounts.getEventEmitter();
|
|
while (true) {
|
|
DcEvent event = emitter.getNextEvent();
|
|
if (event==null) {
|
|
break;
|
|
}
|
|
eventCenter.handleEvent(event);
|
|
}
|
|
Log.i("DeltaChat", "shutting down event handler");
|
|
}, "eventThread").start();
|
|
|
|
// migrating global notifications pref. to per-account config, added 10/July/24
|
|
final String NOTIFICATION_PREF = "pref_key_enable_notifications";
|
|
boolean isMuted = !Prefs.getBooleanPreference(this, NOTIFICATION_PREF, true);
|
|
if (isMuted) {
|
|
for (int accId : dcAccounts.getAll()) {
|
|
dcAccounts.getAccount(accId).setMuted(true);
|
|
}
|
|
Prefs.removePreference(this, NOTIFICATION_PREF);
|
|
}
|
|
// /migrating global notifications
|
|
|
|
for (int accountId : allAccounts) {
|
|
dcAccounts.getAccount(accountId).setConfig(CONFIG_VERIFIED_ONE_ON_ONE_CHATS, "1");
|
|
}
|
|
|
|
// set translations before starting I/O to avoid sending untranslated MDNs (issue #2288)
|
|
DcHelper.setStockTranslations(this);
|
|
|
|
dcAccounts.startIo();
|
|
|
|
new ForegroundDetector(ApplicationContext.getInstance(this));
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
ConnectivityManager connectivityManager =
|
|
(ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
connectivityManager.registerDefaultNetworkCallback(new ConnectivityManager.NetworkCallback() {
|
|
@Override
|
|
public void onAvailable(@NonNull android.net.Network network) {
|
|
Log.i("DeltaChat", "++++++++++++++++++ NetworkCallback.onAvailable() #" + debugOnAvailableCount++);
|
|
dcAccounts.maybeNetwork();
|
|
}
|
|
|
|
@Override
|
|
public void onBlockedStatusChanged(@NonNull android.net.Network network, boolean blocked) {
|
|
Log.i("DeltaChat", "++++++++++++++++++ NetworkCallback.onBlockedStatusChanged() #" + debugOnBlockedStatusChangedCount++);
|
|
}
|
|
|
|
@Override
|
|
public void onCapabilitiesChanged(@NonNull android.net.Network network, NetworkCapabilities networkCapabilities) {
|
|
// usually called after onAvailable(), so a maybeNetwork seems contraproductive
|
|
Log.i("DeltaChat", "++++++++++++++++++ NetworkCallback.onCapabilitiesChanged() #" + debugOnCapabilitiesChangedCount++);
|
|
}
|
|
|
|
@Override
|
|
public void onLinkPropertiesChanged(@NonNull android.net.Network network, LinkProperties linkProperties) {
|
|
Log.i("DeltaChat", "++++++++++++++++++ NetworkCallback.onLinkPropertiesChanged() #" + debugOnLinkPropertiesChangedCount++);
|
|
}
|
|
});
|
|
} // no else: use old method for debugging
|
|
BroadcastReceiver networkStateReceiver = new NetworkStateReceiver();
|
|
registerReceiver(networkStateReceiver, new IntentFilter(android.net.ConnectivityManager.CONNECTIVITY_ACTION));
|
|
|
|
KeepAliveService.maybeStartSelf(this);
|
|
|
|
initializeLogging();
|
|
initializeJobManager();
|
|
InChatSounds.getInstance(this);
|
|
|
|
dcLocationManager = new DcLocationManager(this);
|
|
DynamicTheme.setDefaultDayNightMode(this);
|
|
|
|
IntentFilter filter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
|
|
registerReceiver(new BroadcastReceiver() {
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
Util.localeChanged();
|
|
DcHelper.setStockTranslations(context);
|
|
}
|
|
}, filter);
|
|
|
|
// MAYBE TODO: i think the ApplicationContext is also created
|
|
// when the app is stated by FetchWorker timeouts.
|
|
// in this case, the normal threads shall not be started.
|
|
Constraints constraints = new Constraints.Builder()
|
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
|
.build();
|
|
PeriodicWorkRequest fetchWorkRequest = new PeriodicWorkRequest.Builder(
|
|
FetchWorker.class,
|
|
PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS, // usually 15 minutes
|
|
TimeUnit.MILLISECONDS,
|
|
PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS, // the start may be preferred by up to 5 minutes, so we run every 10-15 minutes
|
|
TimeUnit.MILLISECONDS)
|
|
.setConstraints(constraints)
|
|
.build();
|
|
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
|
|
"FetchWorker",
|
|
ExistingPeriodicWorkPolicy.KEEP,
|
|
fetchWorkRequest);
|
|
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
|
|
|
|
if (Prefs.isPushEnabled(this)) {
|
|
FcmReceiveService.register(this);
|
|
} else {
|
|
Log.i(TAG, "FCM disabled at build time");
|
|
}
|
|
}
|
|
|
|
public JobManager getJobManager() {
|
|
return jobManager;
|
|
}
|
|
|
|
private void initializeLogging() {
|
|
SignalProtocolLoggerProvider.setProvider(new AndroidSignalProtocolLogger());
|
|
}
|
|
|
|
private void initializeJobManager() {
|
|
this.jobManager = new JobManager(this, 5);
|
|
}
|
|
}
|