package cgeo.geocaching; import cgeo.geocaching.playservices.LocationProvider; import cgeo.geocaching.sensors.GeoData; import cgeo.geocaching.sensors.GeoDataProvider; import cgeo.geocaching.sensors.GpsStatusProvider; import cgeo.geocaching.sensors.GpsStatusProvider.Status; import cgeo.geocaching.sensors.IGeoData; import cgeo.geocaching.sensors.OrientationProvider; import cgeo.geocaching.sensors.RotationProvider; import cgeo.geocaching.settings.Settings; import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.OOMDumpingUncaughtExceptionHandler; import cgeo.geocaching.utils.RxUtils; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import org.eclipse.jdt.annotation.NonNull; import rx.Observable; import rx.functions.Action1; import rx.functions.Func1; import android.app.Application; import android.view.ViewConfiguration; import java.lang.reflect.Field; public class CgeoApplication extends Application { private boolean forceRelog = false; // c:geo needs to log into cache providers public boolean showLoginToast = true; //login toast shown just once. private boolean liveMapHintShownInThisSession = false; // livemap hint has been shown private static CgeoApplication instance; private Observable geoDataObservable; private Observable geoDataObservableLowPower; private Observable directionObservable; private Observable gpsStatusObservable; @NonNull private volatile IGeoData currentGeo = GeoData.DUMMY_LOCATION; private volatile boolean hasValidLocation = false; private volatile float currentDirection = 0.0f; private boolean isGooglePlayServicesAvailable = false; private final Action1 rememberGeodataAction = new Action1() { @Override public void call(final IGeoData geoData) { currentGeo = geoData; hasValidLocation = true; } }; public static void dumpOnOutOfMemory(final boolean enable) { if (enable) { if (!OOMDumpingUncaughtExceptionHandler.activateHandler()) { Log.e("OOM dumping handler not activated (either a problem occured or it was already active)"); } } else { if (!OOMDumpingUncaughtExceptionHandler.resetToDefault()) { Log.e("OOM dumping handler not resetted (either a problem occured or it was not active)"); } } } public CgeoApplication() { setInstance(this); } private static void setInstance(final CgeoApplication application) { instance = application; } public static CgeoApplication getInstance() { return instance; } @Override public void onCreate() { 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) { } // Set language to English if the user decided so. Settings.setLanguage(Settings.isUseEnglish()); // ensure initialization of lists DataStore.getLists(); // Check if Google Play services is available if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) { isGooglePlayServicesAvailable = true; } Log.i("Google Play services are " + (isGooglePlayServicesAvailable ? "" : "not ") + "available"); setupGeoDataObservables(Settings.useGooglePlayServices(), Settings.useLowPowerMode()); setupDirectionObservable(Settings.useLowPowerMode()); gpsStatusObservable = GpsStatusProvider.create(this).replay(1).refCount(); // Attempt to acquire an initial location before any real activity happens. geoDataObservableLowPower.subscribeOn(RxUtils.looperCallbacksScheduler).first().subscribe(rememberGeodataAction); } public void setupGeoDataObservables(final boolean useGooglePlayServices, final boolean useLowPowerLocation) { if (useGooglePlayServices) { geoDataObservable = LocationProvider.getMostPrecise(this).doOnNext(rememberGeodataAction); if (useLowPowerLocation) { geoDataObservableLowPower = LocationProvider.getLowPower(this, true).doOnNext(rememberGeodataAction); } else { geoDataObservableLowPower = geoDataObservable; } } else { geoDataObservable = GeoDataProvider.create(this).replay(1).refCount().doOnNext(rememberGeodataAction); geoDataObservableLowPower = geoDataObservable; } } public void setupDirectionObservable(final boolean useLowPower) { directionObservable = RotationProvider.create(this, useLowPower).onErrorResumeNext(new Func1>() { @Override public Observable call(final Throwable throwable) { return OrientationProvider.create(CgeoApplication.this); } }).onErrorResumeNext(new Func1>() { @Override public Observable call(final Throwable throwable) { Log.e("Device orientation will not be available as no suitable sensors were found"); return Observable.never().startWith(0.0f); } }).replay(1).refCount().doOnNext(new Action1() { @Override public void call(final Float direction) { currentDirection = direction; } }); } @Override public void onLowMemory() { Log.i("Cleaning applications cache."); DataStore.removeAllFromCache(); } public Observable geoDataObservable(final boolean lowPower) { return lowPower ? geoDataObservableLowPower : geoDataObservable; } public Observable directionObservable() { return directionObservable; } public Observable gpsStatusObservable() { if (gpsStatusObservable == null) { gpsStatusObservable = GpsStatusProvider.create(this).share(); } return gpsStatusObservable; } @NonNull public IGeoData currentGeo() { return currentGeo; } public boolean hasValidLocation() { return hasValidLocation; } public Float distanceNonBlocking(final ICoordinates target) { if (target.getCoords() == null) { return null; } return currentGeo.getCoords().distanceTo(target); } public float currentDirection() { return currentDirection; } public boolean isLiveMapHintShownInThisSession() { return liveMapHintShownInThisSession; } public void setLiveMapHintShownInThisSession() { liveMapHintShownInThisSession = true; } /** * Check if cgeo must relog even if already logged in. * * @return true if it is necessary to relog */ public boolean mustRelog() { final boolean mustLogin = forceRelog; forceRelog = false; return mustLogin; } /** * Force cgeo to relog when reaching the main activity. */ public void forceRelog() { forceRelog = true; } public boolean isGooglePlayServicesAvailable() { return isGooglePlayServicesAvailable; } }