<commit_before>package cgeo.geocaching;

import cgeo.geocaching.sensors.DirectionProvider;
import cgeo.geocaching.sensors.GeoDataProvider;
import cgeo.geocaching.sensors.IGeoData;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.Log;

import org.apache.commons.lang3.tuple.ImmutablePair;
import rx.Observable;
import rx.functions.Func2;

import android.app.Activity;
import android.app.Application;
import android.app.ProgressDialog;
import android.content.res.Resources;

import java.util.concurrent.atomic.AtomicBoolean;

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<ImmutablePair<IGeoData,Float>> geoDir;

    public CgeoApplication() {
        setInstance(this);
    }

    private static void setInstance(final CgeoApplication application) {
        instance = application;
    }

    public static CgeoApplication getInstance() {
        return instance;
    }

    @Override
    public void onLowMemory() {
        Log.i("Cleaning applications cache.");
        DataStore.removeAllFromCache();
    }

    /**
     * Move the database to/from external cgdata in a new thread,
     * showing a progress window
     *
     * @param fromActivity
     */
    public void moveDatabase(final Activity fromActivity) {
        final Resources res = this.getResources();
        final ProgressDialog dialog = ProgressDialog.show(fromActivity, res.getString(R.string.init_dbmove_dbmove), res.getString(R.string.init_dbmove_running), true, false);
        final AtomicBoolean atomic = new AtomicBoolean(false);
        new Thread() {
            @Override
            public void run() {
                atomic.set(DataStore.moveDatabase());
                fromActivity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        dialog.dismiss();
                        boolean success = atomic.get();
                        String message = success ? res.getString(R.string.init_dbmove_success) : res.getString(R.string.init_dbmove_failed);
                        Dialogs.message(fromActivity, R.string.init_dbmove_dbmove, message);
                    }
                });
            }
        }.start();
    }

    public Observable<ImmutablePair<IGeoData, Float>> geoDirObservable() {
        if (geoDir == null) {
            synchronized(this) {
                if (geoDir == null) {
                    geoDir = Observable.combineLatest(GeoDataProvider.create(this), DirectionProvider.create(this), new Func2<IGeoData, Float, ImmutablePair<IGeoData, Float>>() {
                        @Override
                        public ImmutablePair<IGeoData, Float> call(final IGeoData geoData, final Float dir) {
                            return new ImmutablePair<IGeoData, Float>(geoData, dir);
                        }
                    });
                }
            }
        }
        return geoDir;
    }

    private ImmutablePair<IGeoData, Float> currentGeoDir() {
        return geoDirObservable().first().toBlockingObservable().single();
    }

    public IGeoData currentGeo() {
        return currentGeoDir().left;
    }

    public Float currentDirection() {
        return currentGeoDir().right;
    }

    public boolean isLiveMapHintShownInThisSession() {
        return liveMapHintShownInThisSession;
    }

    public void setLiveMapHintShownInThisSession() {
        liveMapHintShownInThisSession = true;
    }

    /**
     * Check if cgeo must relog even if already logged in.
     *
     * @return <code>true</code> if it is necessary to relog
     */
    public boolean mustRelog() {
        final boolean mustLogin = forceRelog;<commit_msg>Use basic synchronization on infrequent access pattern<commit_after>package cgeo.geocaching;

import cgeo.geocaching.sensors.DirectionProvider;
import cgeo.geocaching.sensors.GeoDataProvider;
import cgeo.geocaching.sensors.IGeoData;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.Log;

import org.apache.commons.lang3.tuple.ImmutablePair;
import rx.Observable;
import rx.functions.Func2;

import android.app.Activity;
import android.app.Application;
import android.app.ProgressDialog;
import android.content.res.Resources;

import java.util.concurrent.atomic.AtomicBoolean;

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<ImmutablePair<IGeoData,Float>> geoDir;

    public CgeoApplication() {
        setInstance(this);
    }

    private static void setInstance(final CgeoApplication application) {
        instance = application;
    }

    public static CgeoApplication getInstance() {
        return instance;
    }

    @Override
    public void onLowMemory() {
        Log.i("Cleaning applications cache.");
        DataStore.removeAllFromCache();
    }

    /**
     * Move the database to/from external cgdata in a new thread,
     * showing a progress window
     *
     * @param fromActivity
     */
    public void moveDatabase(final Activity fromActivity) {
        final Resources res = this.getResources();
        final ProgressDialog dialog = ProgressDialog.show(fromActivity, res.getString(R.string.init_dbmove_dbmove), res.getString(R.string.init_dbmove_running), true, false);
        final AtomicBoolean atomic = new AtomicBoolean(false);
        new Thread() {
            @Override
            public void run() {
                atomic.set(DataStore.moveDatabase());
                fromActivity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        dialog.dismiss();
                        boolean success = atomic.get();
                        String message = success ? res.getString(R.string.init_dbmove_success) : res.getString(R.string.init_dbmove_failed);
                        Dialogs.message(fromActivity, R.string.init_dbmove_dbmove, message);
                    }
                });
            }
        }.start();
    }

    public synchronized Observable<ImmutablePair<IGeoData, Float>> geoDirObservable() {
        if (geoDir == null) {
            geoDir = Observable.combineLatest(GeoDataProvider.create(this), DirectionProvider.create(this), new Func2<IGeoData, Float, ImmutablePair<IGeoData, Float>>() {
                @Override
                public ImmutablePair<IGeoData, Float> call(final IGeoData geoData, final Float dir) {
                    return new ImmutablePair<IGeoData, Float>(geoData, dir);
                }
            });
        }
        return geoDir;
    }

    private ImmutablePair<IGeoData, Float> currentGeoDir() {
        return geoDirObservable().first().toBlockingObservable().single();
    }

    public IGeoData currentGeo() {
        return currentGeoDir().left;
    }

    public Float currentDirection() {
        return currentGeoDir().right;
    }

    public boolean isLiveMapHintShownInThisSession() {
        return liveMapHintShownInThisSession;
    }

    public void setLiveMapHintShownInThisSession() {
        liveMapHintShownInThisSession = true;
    }

    /**
     * Check if cgeo must relog even if already logged in.
     *
     * @return <code>true</code> if it is necessary to relog
     */
    public boolean mustRelog() {
        final boolean mustLogin = forceRelog;
{'fraction_non_alphanumeric': 0.08796237447565781, 'fraction_numerical': 0.0007626795474768018, 'mean_word_length': 2.50467706013363, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4246740', 'n_tokens_mistral': 2158, 'n_tokens_neox': 2071, 'n_words': 492}