package cgeo.geocaching;
import cgeo.geocaching.network.Cookies;
import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.storage.DataStore;
import cgeo.geocaching.utils.AndroidRxUtils;
import cgeo.geocaching.utils.Log;
import cgeo.geocaching.utils.OOMDumpingUncaughtExceptionHandler;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Application;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.os.UserManager;
import android.support.annotation.NonNull;
import android.view.ViewConfiguration;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import com.squareup.leakcanary.LeakCanary;
public class CgeoApplication extends Application {
private static CgeoApplication instance;
public CgeoApplication() {
setInstance(this);
}
private static void setInstance(@NonNull final CgeoApplication application) {
instance = application;
}
public static Application getInstance() {
return instance;
}
@Override
public void onCreate() {
super.onCreate();
OOMDumpingUncaughtExceptionHandler.installUncaughtExceptionHandler();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
fixUserManagerMemoryLeak();
}
LeakCanary.install(this);
showOverflowMenu();
initApplicationLocale();
// ensure initialization of lists
DataStore.getLists();
// Restore cookies
Cookies.restoreCookies();
final Sensors sensors = Sensors.getInstance();
sensors.setupGeoDataObservables(Settings.useGooglePlayServices(), Settings.useLowPowerMode());
sensors.setupDirectionObservable();
// Attempt to acquire an initial location before any real activity happens.
sensors.geoDataObservable(true).subscribeOn(AndroidRxUtils.looperCallbacksScheduler).take(1).subscribe();
}
/**
* https://code.google.com/p/android/issues/detail?id=173789
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void fixUserManagerMemoryLeak() {
try {
// invoke UserManager.get() via reflection
final Method m = UserManager.class.getMethod("get", Context.class);
m.setAccessible(true);
m.invoke(null, this);
} catch (final Throwable e) {
if (BuildConfig.DEBUG) {
throw new IllegalStateException("Cannot fix UserManager memory leak", e);
}
}
}
@Override
public void onConfigurationChanged(final Configuration newConfig) {
super.onConfigurationChanged(newConfig);
initApplicationLocale();
}
private void showOverflowMenu() {
try {
final ViewConfiguration config = ViewConfiguration.get(this);
final Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException ignored) {
}
}
@Override
public void onLowMemory() {
super.onLowMemory();
onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
}
@SuppressLint("NewApi")
@Override
public void onTrimMemory(final int level) {
super.onTrimMemory(level);
if (level >= TRIM_MEMORY_MODERATE) {
Log.i("Cleaning applications cache to trim memory");
DataStore.removeAllFromCache();
}
}
/**
* Enforce language to be English if the user decided so.
*/
private void initApplicationLocale() {
final Configuration config = new Configuration();
config.locale = Settings.getApplicationLocale();
final Resources resources = getResources();
resources.updateConfiguration(config, resources.getDisplayMetrics());
}
}