org.jraf.android.bikey.app.collect.LogCollectorService.java Source code

Java tutorial

Introduction

Here is the source code for org.jraf.android.bikey.app.collect.LogCollectorService.java

Source

/*
 * This source is part of the
 *      _____  ___   ____
 *  __ / / _ \/ _ | / __/___  _______ _
 * / // / , _/ __ |/ _/_/ _ \/ __/ _ `/
 * \___/_/|_/_/ |_/_/ (_)___/_/  \_, /
 *                              /___/
 * repository.
 *
 * Copyright (C) 2013 Benoit 'BoD' Lubek (BoD@JRAF.org)
 *
 * This program 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.
 *
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.jraf.android.bikey.app.collect;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.location.Location;
import android.location.LocationListener;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;

import org.jraf.android.bikey.R;
import org.jraf.android.bikey.app.display.DisplayActivity;
import org.jraf.android.bikey.app.smartwatchsender.AndroidWearSender;
import org.jraf.android.bikey.app.smartwatchsender.PebbleSender;
import org.jraf.android.bikey.backend.cadence.CadenceListener;
import org.jraf.android.bikey.backend.cadence.CadenceManager;
import org.jraf.android.bikey.backend.heartrate.HeartRateListener;
import org.jraf.android.bikey.backend.heartrate.HeartRateManager;
import org.jraf.android.bikey.backend.location.LocationManager;
import org.jraf.android.bikey.backend.log.LogManager;
import org.jraf.android.bikey.backend.ride.RideManager;
import org.jraf.android.bikey.common.Constants;
import org.jraf.android.util.log.Log;
import org.jraf.android.util.string.StringUtil;

import com.getpebble.android.kit.PebbleKit;

public class LogCollectorService extends Service {
    private static final String PREFIX = LogCollectorService.class.getName() + ".";
    public static final String ACTION_START_COLLECTING = PREFIX + "ACTION_START_COLLECTING";
    public static final String ACTION_STOP_COLLECTING = PREFIX + "ACTION_STOP_COLLECTING";

    private static final int NOTIFICATION_ID = 1;
    private Uri mCollectingRideUri;
    protected Location mLastLocation;
    private Float mLastCadence;
    private Integer mLastHeartRate;
    private SharedPreferences mPreferences;
    private AndroidWearSender mAndroidWearSender = null;
    private PebbleSender mPebbleSender = null;

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

    public void onCreate() {
        super.onCreate();
        mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
    }

    @Override
    public int onStartCommand(final Intent intent, int flags, int startId) {
        Log.d("intent=" + StringUtil.toString(intent));
        if (intent == null)
            return Service.START_STICKY;
        String action = intent.getAction();
        if (ACTION_START_COLLECTING.equals(action)) {
            startCollecting(intent.getData());
        } else if (ACTION_STOP_COLLECTING.equals(action)) {
            stopCollecting(intent.getData());
        }
        return Service.START_STICKY;
    }

    private void startCollecting(final Uri rideUri) {
        final Context context = getApplicationContext();
        runOnBackgroundThread(new Runnable() {
            @Override
            public void run() {
                // Smartwatches support (if enabled in prefs)
                if (mPreferences.getBoolean(Constants.PREF_ANDROID_WEAR, Constants.PREF_ANDROID_WEAR_DEFAULT)) {
                    mAndroidWearSender = new AndroidWearSender();
                    mAndroidWearSender.startSending(context);
                }
                if (mPreferences.getBoolean(Constants.PREF_PEBBLE, Constants.PREF_PEBBLE_DEFAULT)
                        && PebbleKit.isWatchConnected(context)) {
                    mPebbleSender = new PebbleSender();
                    mPebbleSender.startSending(LogCollectorService.this);
                }

                // First, pause current ride if any
                if (mCollectingRideUri != null) {
                    RideManager.get().pause(mCollectingRideUri);
                }

                // Check if the ride still exists (it may have been deleted)
                boolean rideExists = RideManager.get().isExistingRide(rideUri);
                Log.d("rideExists=" + rideExists);
                if (!rideExists) {
                    stopSelf();
                    return;
                }

                // Save the ride as the current one
                RideManager.get().setCurrentRide(rideUri);

                // Now collect for the new current ride
                mCollectingRideUri = rideUri;
                RideManager.get().activate(mCollectingRideUri);

                // Show notification
                Notification notification = createNotification();
                startForeground(NOTIFICATION_ID, notification);

                // Start recording location
                LocationManager.get().addLocationListener(mLocationListener);

                // Start monitoring cadence (if enabled in the prefs)
                if (mPreferences.getBoolean(Constants.PREF_RECORD_CADENCE, Constants.PREF_RECORD_CADENCE_DEFAULT)) {
                    CadenceManager.get().addListener(mCadenceListener);
                }

                // Start listening to pref changes (to enable / disable cadence recording accordingly)
                mPreferences.registerOnSharedPreferenceChangeListener(mOnSharedPreferenceChangeListener);

                // Start recording heart rate
                HeartRateManager.get().addListener(mHeartRateListener);
            }
        });
    }

    private void stopCollecting(final Uri rideUri) {
        runOnBackgroundThread(new Runnable() {
            @Override
            public void run() {
                RideManager.get().pause(rideUri);
            }
        });

        // Dismiss notification
        dismissNotification();

        LocationManager.get().removeLocationListener(mLocationListener);
        CadenceManager.get().removeListener(mCadenceListener);
        HeartRateManager.get().removeListener(mHeartRateListener);

        mCollectingRideUri = null;
        stopSelf();
    }

    private void runOnBackgroundThread(final Runnable runnable) {
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                runnable.run();
                return null;
            }
        }.execute();
    }

    /*
     * Location listener.
     */

    private LocationListener mLocationListener = new LocationListener() {
        @Override
        public void onLocationChanged(final Location location) {
            runOnBackgroundThread(new Runnable() {
                @Override
                public void run() {
                    LogManager.get().add(mCollectingRideUri, location, mLastLocation, mLastCadence, mLastHeartRate);
                    mLastLocation = location;
                }
            });
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }

        @Override
        public void onProviderEnabled(String provider) {
        }

        @Override
        public void onProviderDisabled(String provider) {
        }
    };

    /*
     * Cadence listener.
     */

    private CadenceListener mCadenceListener = new CadenceListener() {
        @Override
        public void onCadenceChanged(Float cadence, float[][] rawData) {
            mLastCadence = cadence;
        }
    };

    /*
     * Pref listener.
     */

    protected OnSharedPreferenceChangeListener mOnSharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
        @Override
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            if (mPreferences.getBoolean(Constants.PREF_RECORD_CADENCE, Constants.PREF_RECORD_CADENCE_DEFAULT)) {
                // Start monitoring cadence
                CadenceManager.get().addListener(mCadenceListener);
            } else {
                // Stop monitoring cadence
                CadenceManager.get().removeListener(mCadenceListener);
            }

            // TODO check for smartwatch preferences and start / stop sending values
        }
    };

    /*
     * Heart rate listener.
     */

    private HeartRateListener mHeartRateListener = new HeartRateListener() {
        @Override
        public void onConnecting() {
        }

        @Override
        public void onHeartRateChange(int bpm) {
            mLastHeartRate = bpm;
        }

        @Override
        public void onDisconnected() {
            mLastHeartRate = null;
        }

        @Override
        public void onConnected() {
        }

        @Override
        public void onError() {
            onDisconnected();
        }
    };

    /*
     * Notification.
     */

    private Notification createNotification() {
        NotificationCompat.Builder mainNotifBuilder = new NotificationCompat.Builder(this);
        mainNotifBuilder.setOngoing(true);
        mainNotifBuilder.setSmallIcon(R.drawable.ic_stat_collecting);
        mainNotifBuilder.setTicker(getString(R.string.service_notification_ticker));
        mainNotifBuilder.setContentTitle(getString(R.string.app_name));
        mainNotifBuilder.setContentText(getString(R.string.service_notification_text));
        mainNotifBuilder.setPriority(NotificationCompat.PRIORITY_MAX);

        //        Intent intent = new Intent(this, DisplayActivity.class).setData(mCollectingRideUri);
        //        builder.setContentIntent(PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));

        TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(this);
        taskStackBuilder.addParentStack(DisplayActivity.class);
        Log.d("mCollectingRideUri=" + mCollectingRideUri);
        Intent intent = new Intent(this, DisplayActivity.class).setData(mCollectingRideUri);
        taskStackBuilder.addNextIntent(intent);
        mainNotifBuilder.setContentIntent(taskStackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT));

        //TODO
        //        builder.addAction(R.drawable.ic_action_stop, getString(R.string.service_notification_action_stop),
        //                PendingIntent.getBroadcast(this, 0, new Intent(ACTION_DISABLE), PendingIntent.FLAG_CANCEL_CURRENT));
        //        builder.addAction(R.drawable.ic_action_logs, getString(R.string.service_notification_action_logs),
        //                PendingIntent.getActivity(this, 0, new Intent(this, LogActivity.class), PendingIntent.FLAG_UPDATE_CURRENT));

        Notification notification = mainNotifBuilder.build();
        return notification;
    }

    private void dismissNotification() {
        NotificationManager notificationManager = (NotificationManager) getSystemService(
                Context.NOTIFICATION_SERVICE);
        notificationManager.cancel(NOTIFICATION_ID);
    }

    @Override
    public void onDestroy() {
        // Disconnect smartwatch senders
        if (mAndroidWearSender != null)
            mAndroidWearSender.stopSending();
        if (mPebbleSender != null)
            mPebbleSender.stopSending();

        // Unregister pref listener
        PreferenceManager.getDefaultSharedPreferences(LogCollectorService.this)
                .unregisterOnSharedPreferenceChangeListener(mOnSharedPreferenceChangeListener);
        super.onDestroy();
    }
}