package cgeo.geocaching;

import android.annotation.SuppressLint;
import android.app.Application;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.view.ViewConfiguration;

import com.squareup.leakcanary.LeakCanary;

import android.support.annotation.NonNull;

import java.lang.reflect.Field;

import cgeo.geocaching.compatibility.Compatibility;
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;

public class CgeoApplication extends Application {

    private static CgeoApplication instance;

    public static void dumpOnOutOfMemory(final boolean enable) {

        if (enable) {

            if (!OOMDumpingUncaughtExceptionHandler.activateHandler()) {
                Log.e("OOM dumping handler not activated (either a problem occurred or it was already active)");
            }
        } else if (!OOMDumpingUncaughtExceptionHandler.resetToDefault()) {
            Log.e("OOM dumping handler not resetted (either a problem occurred or it was not active)");
        }
    }

    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();
        LeakCanary.install(this);
        showOverflowMenu();

        initApplicationLocale();

        // ensure initialization of lists
        DataStore.getLists();

        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).first().subscribe();
    }

    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(Compatibility.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());
    }

}

@@ -30,201 +30,264 @@
 ort 
-android.annotation.SuppressLint;%0Aimport android.app.Application;%0Aimport android.content.res.Configuration;%0Aimport android.content.res.Resources;%0Aimport android.view.ViewConfiguration
+cgeo.geocaching.compatibility.Compatibility;%0Aimport cgeo.geocaching.sensors.Sensors;%0Aimport cgeo.geocaching.settings.Settings;%0Aimport cgeo.geocaching.storage.DataStore;%0Aimport cgeo.geocaching.utils.AndroidRxUtils;%0Aimport cgeo.geocaching.utils.Log
 ;%0A
-%0A
 import c
 om.s
@@ -286,439 +286,533 @@
 rt c
-om.squareup.leakcanary.LeakCanary;%0A%0Aimport android.support.annotation.NonNull;%0A%0Aimport java.lang.reflect.Field
+geo.geocaching.utils.OOMDumpingUncaughtExceptionHandler;%0A%0Aimport android.annotation.SuppressLint;%0Aimport android.annotation.TargetApi;%0Aimport android.app.Application
 ;%0A
-%0A
 import 
-cgeo.geocaching.compatibility.Compatibility;%0Aimport cgeo.geocaching.sensors.Sensors;%0Aimport cgeo.geocaching.settings.Settings;%0Aimport cgeo.geocaching.storage.DataStore;%0Aimport cgeo.geocaching.utils.AndroidRxUtils;%0Aimport cgeo.geocaching.utils.Log;%0Aimport cgeo.geocaching.utils.OOMDumpingUncaughtExceptionHandler
+android.content.Context;%0Aimport android.content.res.Configuration;%0Aimport android.content.res.Resources;%0Aimport android.os.Build;%0Aimport android.os.UserManager;%0Aimport android.support.annotation.NonNull;%0Aimport android.view.ViewConfiguration;%0A%0Aimport java.lang.reflect.Field;%0Aimport java.lang.reflect.Method;%0A%0Aimport com.squareup.leakcanary.LeakCanary
 ;%0A%0Ap
@@ -1722,24 +1722,151 @@
 onCreate();%0A
+%0A        if (Build.VERSION.SDK_INT %3E= Build.VERSION_CODES.JELLY_BEAN_MR1) %7B%0A            fixUserManagerMemoryLeak();%0A        %7D%0A%0A
         Leak
@@ -2423,32 +2423,607 @@
 cribe();%0A    %7D%0A%0A
+    /**%0A     * https://code.google.com/p/android/issues/detail?id=173789%0A     */%0A    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)%0A    private void fixUserManagerMemoryLeak() %7B%0A        try %7B%0A            final Method m = UserManager.class.getMethod(%22get%22, Context.class);%0A            m.setAccessible(true);%0A            m.invoke(null, this);%0A%0A            //above is reflection for below...%0A            //UserManager.get();%0A        %7D catch (final Throwable e) %7B%0A            if (BuildConfig.DEBUG) %7B%0A                throw new RuntimeException(e);%0A            %7D%0A        %7D%0A    %7D%0A%0A
     private void

fix memory leak in Android UserManager