/*
* The CroudTrip! application aims at revolutionizing the car-ride-sharing market with its easy,
* user-friendly and highly automated way of organizing shared Trips. Copyright (C) 2015 Nazeeh Ammari,
* Philipp Eichhorn, Ricarda Hohn, Vanessa Lange, Alexander Popp, Frederik Simon, Michael Weber
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU
* Affero 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 Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public License along with this program.
* If not, see http://www.gnu.org/licenses/.
*/
package org.croudtrip.location;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Location;
import android.support.v4.app.NotificationCompat;
import org.croudtrip.Constants;
import org.croudtrip.R;
import org.croudtrip.api.TripsResource;
import org.croudtrip.api.directions.RouteLocation;
import org.croudtrip.api.trips.TripOffer;
import org.croudtrip.api.trips.TripOfferUpdate;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import javax.inject.Inject;
import pl.charmas.android.reactivelocation.ReactiveLocationProvider;
import roboguice.receiver.RoboBroadcastReceiver;
import rx.Observable;
import rx.functions.Action1;
import rx.functions.Func1;
import timber.log.Timber;
/**
* Created by Frederik Simon on 17.05.2015.
*/
public class LocationUploadTimerReceiver extends RoboBroadcastReceiver {
private static final int NOTIFICATION_UPLOAD_TIMER = 654;
private final float MIN_ACCURACY = 200.0f;
private final int MAX_FAILURE_COUNT = 3;
@Inject
private LocationUpdater locationUpdater;
@Inject
private TripsResource tripsResource;
private static AtomicInteger failureCount = new AtomicInteger();
@Override
protected void handleReceive( final Context context, Intent intent ) {
ReactiveLocationProvider reactiveLocationProvider = new ReactiveLocationProvider(context);
reactiveLocationProvider.getLastKnownLocation()
.subscribe( new Action1<Location>() {
@Override
public void call(final Location location) {
tripsResource.getActiveOffers()
.subscribe(
new Action1<List<TripOffer>>() {
@Override
public void call(List<TripOffer> tripOffers) {
if( tripOffers == null || tripOffers.isEmpty() ) {
Timber.w("You have currently no trips running. No position upload is necessary");
return;
}
if( location == null ) {
// null is not good, but happens on startup, so that's okay.
Timber.e("No Update of location was possible, since location was null");
return;
}
Timber.d("Your location accuracy is " + location.getAccuracy());
if( location.getAccuracy() > MIN_ACCURACY ) {
Timber.e("Your location is not accurate enough: " + location.getAccuracy());
handleError(context);
return;
}
RouteLocation routeLocation = new RouteLocation( location.getLatitude(), location.getLongitude() );
for (final TripOffer offer : tripOffers) {
// TODO: There should only be one offer
TripOfferUpdate offerUpdate = TripOfferUpdate.createNewStartUpdate(routeLocation);
tripsResource.updateOffer(offer.getId(), offerUpdate)
.subscribe( new Action1<TripOffer>() {
@Override
public void call(TripOffer tripOffer) {
Timber.d("Updated your location on the server for offer " + tripOffer.getId());
SharedPreferences prefs = context.getSharedPreferences(Constants.SHARED_PREF_FILE_PREFERENCES, Context.MODE_PRIVATE);
if (prefs.getBoolean(Constants.SHARED_PREF_KEY_RUNNING_TRIP_OFFER, false)) {
handleSuccess(context);
}
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
Timber.e("Was not able to update your location on the server " + offer.getId() + " : " + throwable.getMessage());
SharedPreferences prefs = context.getSharedPreferences(Constants.SHARED_PREF_FILE_PREFERENCES, Context.MODE_PRIVATE);
if (prefs.getBoolean(Constants.SHARED_PREF_KEY_RUNNING_TRIP_OFFER, false)) {
handleError(context);
}
}
});
}
}
},
new Action1<Throwable>(){
@Override
public void call(Throwable throwable) {
Timber.e("Was not able to update your location on the server. Could not download your offers: " + throwable.getMessage());
if (context.getSharedPreferences(Constants.SHARED_PREF_FILE_PREFERENCES, Context.MODE_PRIVATE).getBoolean(Constants.SHARED_PREF_KEY_RUNNING_TRIP_OFFER, false)) {
handleError(context);
}
}
});
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
Timber.e("There was an error retrieving the last Location: " + throwable.getMessage());
}
}
);
}
private void handleSuccess( Context context ) {
int fc = failureCount.getAndSet(0);
Timber.d("Failure Count is " + fc);
if( fc >= MAX_FAILURE_COUNT ){
// show a notification that no position upload was possible
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_directions_car_white)
.setContentTitle(context.getString(R.string.success_position_update_title))
.setStyle(new NotificationCompat.BigTextStyle().bigText(context.getString(R.string.success_position_update_message)))
.setContentText(context.getString(R.string.success_position_update_message))
.build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify( NOTIFICATION_UPLOAD_TIMER, notification );
}
}
private void handleError( Context context ) {
int fc = failureCount.incrementAndGet();
Timber.d("Failure Count is " + fc);
if( fc == MAX_FAILURE_COUNT ){
// show a notification that no position upload was possible
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_directions_car_white)
.setContentTitle(context.getString(R.string.error_position_update_title))
.setStyle(new NotificationCompat.BigTextStyle().bigText(context.getString(R.string.error_position_update_message)))
.setContentText(context.getString(R.string.error_position_update_message))
.build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify( NOTIFICATION_UPLOAD_TIMER, notification );
}
}
}