<commit_before>
package st.alr.mqttitude.services;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import st.alr.mqttitude.App;
import st.alr.mqttitude.db.Waypoint;
import st.alr.mqttitude.db.WaypointDao;
import st.alr.mqttitude.db.WaypointDao.Properties;
import st.alr.mqttitude.model.GeocodableLocation;
import st.alr.mqttitude.model.Report;
import st.alr.mqttitude.preferences.ActivityPreferences;
import st.alr.mqttitude.support.Defaults;
import st.alr.mqttitude.support.Events;
import st.alr.mqttitude.support.MqttPublish;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.location.Location;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.util.Log;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationStatusCodes;

import de.greenrobot.event.EventBus;

public class ServiceLocator implements ProxyableService, MqttPublish, 
        GooglePlayServicesClient.ConnectionCallbacks,
        GooglePlayServicesClient.OnConnectionFailedListener, LocationListener,  LocationClient.OnRemoveGeofencesResultListener,  LocationClient.OnAddGeofencesResultListener {
    
    private SharedPreferences sharedPreferences;
    private OnSharedPreferenceChangeListener preferencesChangedListener;
    private static Defaults.State.ServiceLocator state = Defaults.State.ServiceLocator.INITIAL;
    private ServiceProxy context;

    private LocationClient mLocationClient;
    private LocationRequest mLocationRequest;
    private boolean ready = false;
    private boolean foreground = false;

    private GeocodableLocation lastKnownLocation;
    private Date lastPublish;
    private List<Waypoint> waypoints;
    private WaypointDao waypointDao;
    

    public void onCreate(ServiceProxy p) {
       

                context = p;
                waypointDao = ServiceProxy.getServiceApplication().getWaypointDao();
                loadWaypoints();
        
                this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);

                preferencesChangedListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
                    @Override
                    public void onSharedPreferenceChanged(SharedPreferences sharedPreference, String key) {
                        if(key.equals(Defaults.SETTINGS_KEY_BACKGROUND_UPDATES) || key.equals(Defaults.SETTINGS_KEY_BACKGROUND_UPDATES_INTERVAL))
                            handlePreferences();
                    }
                };
                sharedPreferences.registerOnSharedPreferenceChangeListener(preferencesChangedListener);

                
        mLocationClient = new LocationClient(context, this, this);


        if (!mLocationClient.isConnected() && !mLocationClient.isConnecting() && ServiceApplication.checkPlayServices())
            mLocationClient.connect();

    }

    public GeocodableLocation getLastKnownLocation() {
        return lastKnownLocation;
    }
    
    public void onFenceTransition(Intent intent) {
        int transitionType = LocationClient.getGeofenceTransition(intent);
        
        // Test that a valid transition was reported
        if ( (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER)  || (transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) ) {
            List <Geofence> triggerList = LocationClient.getTriggeringGeofences(intent);

            for (int i = 0; i < triggerList.size(); i++) {
               
                Waypoint w = waypointDao.queryBuilder().where(Properties.GeofenceId.eq(triggerList.get(i).getRequestId())).limit(1).unique();

                Log.v(this.toString(), "Waypoint triggered " + w.getDescription() + " transition: " + transitionType);
                
                if(w != null)
                    publishGeofenceTransitionEvent(w, transitionType);
            }
        }          
    }
    

    @Override
    public void onLocationChanged(Location arg0) {
        Log.v(this.toString(), "onLocationChanged");
        this.lastKnownLocation = new GeocodableLocation(arg0);

        EventBus.getDefault().postSticky(new Events.LocationUpdated(this.lastKnownLocation));

        if (shouldPublishLocation())
            publishLastKnownLocation();        
    }

    private boolean shouldPublishLocation() {
        Date now = new Date();
        if (lastPublish == null)
            return true;

        if (now.getTime() - lastPublish.getTime() > getUpdateIntervallInMiliseconds())
            return true;

        return false;
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.e(this.toString(), "Failed to connect");
    }

    @Override
    public void onConnected(Bundle arg0) {
        ready = true;

        Log.v(this.toString(), "Connected");
        setupLocationRequest();
        requestLocationUpdates();
        
        setupGeofences();
    }

    @Override
    public void onDisconnected() {
        ready = false;
        ServiceApplication.checkPlayServices(); // show error notification if play services were disabled
    }

    private void setupBackgroundLocationRequest() {
        mLocationRequest = LocationRequest.create();
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        mLocationRequest.setInterval(getUpdateIntervallInMiliseconds());
        mLocationRequest.setFastestInterval(0);
        mLocationRequest.setSmallestDisplacement(500);
    }

    private void setupForegroundLocationRequest() {
        mLocationRequest = LocationRequest.create();
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationRequest.setInterval(10 * 1000);
        mLocationRequest.setFastestInterval(0);
        mLocationRequest.setSmallestDisplacement(50);
    }

    protected void handlePreferences() {
        setupLocationRequest();
        requestLocationUpdates();
    }

    private void disableLocationUpdates() {
        Log.v(this.toString(), "Disabling updates");
        if (mLocationClient != null) {
            mLocationClient.removeLocationUpdates(ServiceProxy.getPendingIntentForService(context,
                    ServiceProxy.SERVICE_LOCATOR, Defaults.INTENT_ACTION_LOCATION_CHANGED, null, 0));
        }
    }

    private void requestLocationUpdates() {
        if (!ready) {
            Log.e(this.toString(), "requestLocationUpdates but not connected to play services. Updates will be requested again once connected");
            return;
        }

        if (foreground || areBackgroundUpdatesEnabled()) {
//            locationIntent = ServiceProxy.getPendingIntentForService(context,
//                    ServiceProxy.SERVICE_LOCATOR, Defaults.INTENT_ACTION_LOCATION_CHANGED, null);

            mLocationClient.requestLocationUpdates(mLocationRequest, ServiceProxy.getPendingIntentForService(context,
                    ServiceProxy.SERVICE_LOCATOR, Defaults.INTENT_ACTION_LOCATION_CHANGED, null));<commit_msg>Fixed issue where location services were accessed when not connected<commit_after>
package st.alr.mqttitude.services;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import st.alr.mqttitude.App;
import st.alr.mqttitude.db.Waypoint;
import st.alr.mqttitude.db.WaypointDao;
import st.alr.mqttitude.db.WaypointDao.Properties;
import st.alr.mqttitude.model.GeocodableLocation;
import st.alr.mqttitude.model.Report;
import st.alr.mqttitude.preferences.ActivityPreferences;
import st.alr.mqttitude.support.Defaults;
import st.alr.mqttitude.support.Events;
import st.alr.mqttitude.support.MqttPublish;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.location.Location;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.util.Log;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationStatusCodes;

import de.greenrobot.event.EventBus;

public class ServiceLocator implements ProxyableService, MqttPublish, 
        GooglePlayServicesClient.ConnectionCallbacks,
        GooglePlayServicesClient.OnConnectionFailedListener, LocationListener,  LocationClient.OnRemoveGeofencesResultListener,  LocationClient.OnAddGeofencesResultListener {
    
    private SharedPreferences sharedPreferences;
    private OnSharedPreferenceChangeListener preferencesChangedListener;
    private static Defaults.State.ServiceLocator state = Defaults.State.ServiceLocator.INITIAL;
    private ServiceProxy context;

    private LocationClient mLocationClient;
    private LocationRequest mLocationRequest;
    private boolean ready = false;
    private boolean foreground = false;

    private GeocodableLocation lastKnownLocation;
    private Date lastPublish;
    private List<Waypoint> waypoints;
    private WaypointDao waypointDao;
    

    public void onCreate(ServiceProxy p) {
       

                context = p;
                waypointDao = ServiceProxy.getServiceApplication().getWaypointDao();
                loadWaypoints();
        
                this.sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);

                preferencesChangedListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
                    @Override
                    public void onSharedPreferenceChanged(SharedPreferences sharedPreference, String key) {
                        if(key.equals(Defaults.SETTINGS_KEY_BACKGROUND_UPDATES) || key.equals(Defaults.SETTINGS_KEY_BACKGROUND_UPDATES_INTERVAL))
                            handlePreferences();
                    }
                };
                sharedPreferences.registerOnSharedPreferenceChangeListener(preferencesChangedListener);

                
        mLocationClient = new LocationClient(context, this, this);


        if (!mLocationClient.isConnected() && !mLocationClient.isConnecting() && ServiceApplication.checkPlayServices())
            mLocationClient.connect();

    }

    public GeocodableLocation getLastKnownLocation() {
        return lastKnownLocation;
    }
    
    public void onFenceTransition(Intent intent) {
        int transitionType = LocationClient.getGeofenceTransition(intent);
        
        // Test that a valid transition was reported
        if ( (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER)  || (transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) ) {
            List <Geofence> triggerList = LocationClient.getTriggeringGeofences(intent);

            for (int i = 0; i < triggerList.size(); i++) {
               
                Waypoint w = waypointDao.queryBuilder().where(Properties.GeofenceId.eq(triggerList.get(i).getRequestId())).limit(1).unique();

                Log.v(this.toString(), "Waypoint triggered " + w.getDescription() + " transition: " + transitionType);
                
                if(w != null)
                    publishGeofenceTransitionEvent(w, transitionType);
            }
        }          
    }
    

    @Override
    public void onLocationChanged(Location arg0) {
        Log.v(this.toString(), "onLocationChanged");
        this.lastKnownLocation = new GeocodableLocation(arg0);

        EventBus.getDefault().postSticky(new Events.LocationUpdated(this.lastKnownLocation));

        if (shouldPublishLocation())
            publishLastKnownLocation();        
    }

    private boolean shouldPublishLocation() {
        Date now = new Date();
        if (lastPublish == null)
            return true;

        if (now.getTime() - lastPublish.getTime() > getUpdateIntervallInMiliseconds())
            return true;

        return false;
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.e(this.toString(), "Failed to connect");
    }

    @Override
    public void onConnected(Bundle arg0) {
        ready = true;

        Log.v(this.toString(), "Connected");
        setupLocationRequest();
        requestLocationUpdates();
        
        setupGeofences();
    }

    @Override
    public void onDisconnected() {
        ready = false;
        ServiceApplication.checkPlayServices(); // show error notification if play services were disabled
    }

    private void setupBackgroundLocationRequest() {
        mLocationRequest = LocationRequest.create();
        mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
        mLocationRequest.setInterval(getUpdateIntervallInMiliseconds());
        mLocationRequest.setFastestInterval(0);
        mLocationRequest.setSmallestDisplacement(500);
    }

    private void setupForegroundLocationRequest() {
        mLocationRequest = LocationRequest.create();
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        mLocationRequest.setInterval(10 * 1000);
        mLocationRequest.setFastestInterval(0);
        mLocationRequest.setSmallestDisplacement(50);
    }

    protected void handlePreferences() {
        setupLocationRequest();
        requestLocationUpdates();
    }

    private void disableLocationUpdates() {
        Log.v(this.toString(), "Disabling updates");
        if (mLocationClient != null && mLocationClient.isConnected()) {
            mLocationClient.removeLocationUpdates(ServiceProxy.getPendingIntentForService(context,
                    ServiceProxy.SERVICE_LOCATOR, Defaults.INTENT_ACTION_LOCATION_CHANGED, null, 0));
        }
    }

    private void requestLocationUpdates() {
        if (!ready) {
            Log.e(this.toString(), "requestLocationUpdates but not connected to play services. Updates will be requested again once connected");
            return;
        }

        if (foreground || areBackgroundUpdatesEnabled()) {
//            locationIntent = ServiceProxy.getPendingIntentForService(context,
//                    ServiceProxy.SERVICE_LOCATOR, Defaults.INTENT_ACTION_LOCATION_CHANGED, null);

            mLocationClient.requestLocationUpdates(mLocationRequest, ServiceProxy.getPendingIntentForService(context,
                    ServiceProxy.SERVICE_LOCATOR, Defaults.INTENT_ACTION_LOCATION_CHANGED, null));
{'fraction_non_alphanumeric': 0.08411887928777166, 'fraction_numerical': 0.0024875621890547263, 'mean_word_length': 3.237725381414702, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, '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': '7052856', 'n_tokens_mistral': 4054, 'n_tokens_neox': 3935, 'n_words': 701}