ca.uwaterloo.magic.goodhikes.GPSLoggingService.java Source code

Java tutorial

Introduction

Here is the source code for ca.uwaterloo.magic.goodhikes.GPSLoggingService.java

Source

/*------------------------------------------------------------------------------
 *   Authors: Slavik, George, Thao, Chelsea
 *   Copyright: (c) 2016 Team Magic
 *
 *   This file is part of GoodHikes.
 *
 *   GoodHikes is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   GoodHikes is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with GoodHikes.  If not, see <http://www.gnu.org/licenses/>.
 */
package ca.uwaterloo.magic.goodhikes;

import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Location;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;

import ca.uwaterloo.magic.goodhikes.data.Route;
import ca.uwaterloo.magic.goodhikes.data.RoutesDatabaseManager;
import ca.uwaterloo.magic.goodhikes.data.UserManager;

public class GPSLoggingService extends Service implements LocationListener, GoogleApiClient.ConnectionCallbacks,
        GoogleApiClient.OnConnectionFailedListener {

    protected static final String LOG_TAG = "GPSLoggingService";
    protected GoogleApiClient mGoogleApiClient;
    protected LocationRequest mLocationRequest;
    public static final String locationUpdateCommand = "ca.uwaterloo.magic.goodhikes.location.update";
    private final IBinder mBinder = new LoggingBinder();
    private LooperThread internalLooperThread;
    private boolean mTrackingIsActive = false, trackingIsPaused;
    public Route currentRoute;
    private UserManager userManager;
    private RoutesDatabaseManager database;

    private static class GPSTrackingCommands {
        public static final String START = "ca.uwaterloo.magic.goodhikes.location.update.start";
        public static final String STOP = "ca.uwaterloo.magic.goodhikes.location.update.stop";
    }

    public void startLocationTracking() {
        sendCommandToLooperThread(new Intent(GPSTrackingCommands.START));
        mTrackingIsActive = true;
    }

    public void stopLocationTracking() {
        sendCommandToLooperThread(new Intent(GPSTrackingCommands.STOP));
        mTrackingIsActive = false;
    }

    public void setTrackingOnPause(boolean value) {
        trackingIsPaused = value;
    }

    public boolean isTrackingOnPause() {
        return trackingIsPaused;
    }

    public void saveRoute() {
        database.insertRoute(currentRoute, userManager.getUser());
    }

    private void sendCommandToLooperThread(Intent command) {
        if (internalLooperThread != null) {
            Message msg = internalLooperThread.mLooperThreadHandler.obtainMessage();
            msg.obj = command;
            Log.d(LOG_TAG, "Thread: " + Thread.currentThread().getId() + "; Sending " + command.getAction()
                    + " command to looper thread");
            internalLooperThread.mLooperThreadHandler.sendMessage(msg);
        }
    }

    public boolean isTrackingActive() {
        return mTrackingIsActive;
    }

    public void setTrackingStatus(boolean mTrackingIsActive) {
        this.mTrackingIsActive = mTrackingIsActive;
    }

    public class LoggingBinder extends Binder {
        GPSLoggingService getService() {
            return GPSLoggingService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public void onCreate() {
        //        android.os.Debug.waitForDebugger();
        super.onCreate();
        userManager = new UserManager(getApplicationContext());
        database = RoutesDatabaseManager.getInstance(this);
        createGoogleAPIClient();
        createLocationRequest();
        mGoogleApiClient.connect();
        Log.d(LOG_TAG, "Thread: " + Thread.currentThread().getId() + "; Started GPS tracking service");
    }

    public void stopService() {
        if (mGoogleApiClient.isConnected()) {
            stopLocationTracking();
            mGoogleApiClient.disconnect();
        }
        if (internalLooperThread.mLooper != null) {
            internalLooperThread.mLooper.quit();
            internalLooperThread.interrupt();
        }
        Log.d(LOG_TAG, "Thread: " + Thread.currentThread().getId() + "; Stopped GPS tracking service");
    }

    @Override
    public void onDestroy() {
        stopService();
    }

    private void createGoogleAPIClient() {
        if (mGoogleApiClient == null) {
            mGoogleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this).addApi(LocationServices.API).build();
        }
    }

    private void createLocationRequest() {
        mLocationRequest = new LocationRequest();
        updateGPSfrequency();
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

    //Settings: Change GPS Update Frequency
    public void updateGPSfrequency() {
        if (mLocationRequest != null) {
            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
            int gps_frequency = Integer.parseInt(
                    prefs.getString(getString(R.string.interval_pref), getString(R.string.interval_pref_default)));
            System.out.println("update freq:" + gps_frequency);
            mLocationRequest.setInterval(gps_frequency);
            mLocationRequest.setFastestInterval(gps_frequency);
        }
    }

    private void startLocationTrackingInLooperThread() {
        if (mGoogleApiClient.isConnected() && internalLooperThread.mLooper != null) {
            LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this,
                    internalLooperThread.mLooper);
            mTrackingIsActive = true;

            if (trackingIsPaused) {
                trackingIsPaused = false;
            } else {
                currentRoute = new Route(userManager.getUser());
            }
            Log.d(LOG_TAG,
                    "Thread: " + Thread.currentThread().getId() + "; Starting location tracking in looper thread");
        }
    }

    private void stopLocationTrackingInLooperThread() {
        LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
        mTrackingIsActive = false;
        currentRoute.setDateEnd(System.currentTimeMillis());
        Log.d(LOG_TAG,
                "Thread: " + Thread.currentThread().getId() + "; Stopped location tracking in looper thread");
    }

    /*
    * GoogleApiClient lifecycle callbacks
    * Interfaces: GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener
    * ------------------------------------------------------------------------------------------
    */
    @Override
    public void onConnected(Bundle connectionHint) {
        //        broadcastLastKnownLocation();
        internalLooperThread = new LooperThread();
        internalLooperThread.start();
    }

    @Override
    public void onConnectionSuspended(int i) {
        Log.i(LOG_TAG, "GoogleApiClient connection has been suspended");
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.i(LOG_TAG, "GoogleApiClient connection has failed");
    }

    @Override
    public void onLocationChanged(Location location) {
        Log.d(LOG_TAG, "Thread: " + Thread.currentThread().getId() + "; Location update received");
        currentRoute.addPoint(location);
        broadcastLocation(location);
    }

    private void broadcastLocation(Location location) {
        Log.d(LOG_TAG, "Thread: " + Thread.currentThread().getId() + "; Sending location update");
        Intent intent = new Intent(locationUpdateCommand);
        intent.putExtra(locationUpdateCommand, location);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    public void broadcastLastKnownLocation() {
        if (mGoogleApiClient.isConnected()) {
            Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
            broadcastLocation(location);
        }
    }

    class LooperThread extends Thread {
        private Looper mLooper;
        private Handler mLooperThreadHandler;

        public void run() {
            Looper.prepare();
            mLooper = Looper.myLooper();

            mLooperThreadHandler = new Handler() {
                public void handleMessage(Message msg) {
                    if (msg.obj != null && msg.obj instanceof Intent) {
                        onHandleIntent((Intent) msg.obj);
                    }
                }
            };
            Log.d(LOG_TAG, "Thread: " + Thread.currentThread().getId() + "; Thread looper" + mLooper.toString()
                    + "; Created a runner thread");
            Looper.loop();
        }
    }

    private void onHandleIntent(Intent intent) {
        if (intent.getAction().equals(GPSTrackingCommands.START)) {
            startLocationTrackingInLooperThread();
        } else if (intent.getAction().equals(GPSTrackingCommands.STOP)) {
            stopLocationTrackingInLooperThread();
        }

    }

    public int getTrackingButtonIcon() {
        return isTrackingActive() ? R.drawable.ampelmann_red : R.drawable.ampelmann_green;
    }

    public int getMilestoneButtonIcon() {
        return isTrackingActive() ? R.drawable.ic_room_yellow_18dp : R.drawable.ic_room_disable_18dp;
    }
}