org.croudtrip.gcm.GcmIntentService.java Source code

Java tutorial

Introduction

Here is the source code for org.croudtrip.gcm.GcmIntentService.java

Source

/*
 * 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.gcm;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.LocalBroadcastManager;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.android.gms.gcm.GoogleCloudMessaging;

import org.croudtrip.Constants;
import org.croudtrip.R;
import org.croudtrip.activities.MainActivity;
import org.croudtrip.api.TripsResource;
import org.croudtrip.api.directions.RouteLocation;
import org.croudtrip.api.gcm.GcmConstants;
import org.croudtrip.api.trips.JoinTripRequest;
import org.croudtrip.api.trips.RunningTripQuery;
import org.croudtrip.api.trips.SuperTrip;
import org.croudtrip.api.trips.TripQuery;
import org.croudtrip.fragments.join.JoinDispatchFragment;
import org.croudtrip.utils.LifecycleHandler;

import javax.inject.Inject;

import roboguice.service.RoboIntentService;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.schedulers.Schedulers;
import timber.log.Timber;

/**
 * An intent server that handles the gcm messages comming from the server. It will create notifications
 * so that the user can react on new offered trips or open requests.
 * Created by Frederik Simon on 08.05.2015.
 */
public class GcmIntentService extends RoboIntentService {

    @Inject
    TripsResource tripsResource;

    public GcmIntentService() {
        super("GcmIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        final Context context = getApplicationContext();

        // check for proper GCM message
        String messageType = GoogleCloudMessaging.getInstance(context).getMessageType(intent);
        if (!GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType))
            return;

        // get the type of message and handle it properly
        String gcmMessageType = intent.getExtras().getString(GcmConstants.GCM_TYPE);
        Timber.d(gcmMessageType);

        switch (gcmMessageType) {

        case GcmConstants.GCM_MSG_REQUEST_EXPIRED:
            handleJoinRequestExpired();
            break;
        case GcmConstants.GCM_MSG_DUMMY:
            break;
        case GcmConstants.GCM_MSG_JOIN_REQUEST:
            handleJoinRequest(intent);
            break;
        case GcmConstants.GCM_MSG_REQUEST_ACCEPTED:
            handleRequestAccepted(intent);
            break;
        case GcmConstants.GCM_MSG_REQUEST_DECLINED:
            handleRequestDeclined(intent);
            break;
        case GcmConstants.GCM_MSG_FOUND_MATCHES:
            handleFoundMatches(intent);
            break;
        case GcmConstants.GCM_MESSAGE_TRIP_CANCELLED_BY_DRIVER:
            handleTripCanceledByDriver();
            break;
        case GcmConstants.GCM_MESSAGE_TRIP_CANCELLED_BY_PASSENGER:
            handleTripCanceledByPassenger();
            break;
        case GcmConstants.GCM_MSG_PASSENGER_AT_DESTINATION:
            handlePassengerAtDestination();
            break;
        case GcmConstants.GCM_MSG_PASSENGER_ENTERED_CAR:
            handlePassengerEnteredCar();
            break;
        case GcmConstants.GCM_MSG_ARRIVAL_TIME_UPDATE:
            handleArrivalTimeUpdate(intent);
        default:
            break;
        }

        GcmBroadcastReceiver.completeWakefulIntent(intent);
    }

    private void handleArrivalTimeUpdate(Intent intent) {
        Timber.d("ARRIVAL_TIME_UPDATE");

        // extract join request and offer from message
        final long joinTripRequestId = Long
                .parseLong(intent.getExtras().getString(GcmConstants.GCM_MSG_JOIN_REQUEST_ID));

        // download the join trip request
        tripsResource.getJoinRequest(joinTripRequestId).observeOn(Schedulers.io())
                .subscribeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<JoinTripRequest>() {
                    @Override
                    public void call(JoinTripRequest joinTripRequest) {

                        final SharedPreferences prefs = getApplicationContext()
                                .getSharedPreferences(Constants.SHARED_PREF_FILE_PREFERENCES, Context.MODE_PRIVATE);
                        SharedPreferences.Editor editor = prefs.edit();
                        editor.putBoolean(Constants.SHARED_PREF_KEY_ACCEPTED, true);
                        editor.putBoolean(Constants.SHARED_PREF_KEY_WAITING, false);
                        editor.putBoolean(Constants.SHARED_PREF_KEY_SEARCHING, false);
                        editor.putLong(Constants.SHARED_PREF_KEY_TRIP_ID, joinTripRequest.getId());
                        editor.apply();

                        Bundle extras = new Bundle();
                        ObjectMapper mapper = new ObjectMapper();
                        try {
                            extras.putString(JoinDispatchFragment.KEY_JOIN_TRIP_REQUEST_RESULT,
                                    mapper.writeValueAsString(joinTripRequest));
                        } catch (JsonProcessingException e) {
                            Timber.e("Could not map join trip result");
                            e.printStackTrace();
                        }

                        if (LifecycleHandler.isApplicationInForeground()) {
                            Intent startingIntent = new Intent(Constants.EVENT_CHANGE_JOIN_UI);
                            startingIntent.putExtras(extras);
                            LocalBroadcastManager.getInstance(getApplicationContext())
                                    .sendBroadcast(startingIntent);
                        }

                    }
                }, new Action1<Throwable>() {
                    @Override
                    public void call(Throwable throwable) {
                        Timber.e("Something went wrong when downloading join request: " + throwable.getMessage());
                    }
                });
    }

    private void handlePassengerAtDestination() {
        if (LifecycleHandler.isApplicationInForeground()) {
            // send broadcast while the app is running to reload the application
            Intent startingIntent = new Intent(Constants.EVENT_PASSENGER_REACHED_DESTINATION);
            LocalBroadcastManager.getInstance(this).sendBroadcast(startingIntent);
        }
    }

    private void handlePassengerEnteredCar() {
        if (LifecycleHandler.isApplicationInForeground()) {
            // send broadcast while the app is running to reload the application
            Intent startingIntent = new Intent(Constants.EVENT_PASSENGER_ENTERED_CAR);
            LocalBroadcastManager.getInstance(this).sendBroadcast(startingIntent);
        }
    }

    private void handleFoundMatches(Intent intent) {
        Timber.d("FOUND_MATCHES");

        // extract join request and offer from message
        long queryId = Long.parseLong(intent.getExtras().getString(GcmConstants.GCM_MSG_FOUND_MATCHES_QUERY_ID));

        // download the join trip request
        tripsResource.getQuery(queryId).observeOn(Schedulers.io()).subscribeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<RunningTripQuery>() {
                    @Override
                    public void call(RunningTripQuery query) {

                        final SharedPreferences prefs = getApplicationContext()
                                .getSharedPreferences(Constants.SHARED_PREF_FILE_PREFERENCES, Context.MODE_PRIVATE);
                        SharedPreferences.Editor editor = prefs.edit();
                        editor.putBoolean(Constants.SHARED_PREF_KEY_SEARCHING, true);
                        editor.putBoolean(Constants.SHARED_PREF_KEY_ACCEPTED, false);
                        editor.putLong(Constants.SHARED_PREF_KEY_QUERY_ID, -1);
                        editor.apply();

                        Bundle extras = new Bundle();
                        extras.putDouble(JoinDispatchFragment.KEY_CURRENT_LOCATION_LATITUDE,
                                query.getQuery().getStartLocation().getLat());
                        extras.putDouble(JoinDispatchFragment.KEY_CURRENT_LOCATION_LONGITUDE,
                                query.getQuery().getStartLocation().getLng());
                        extras.putDouble(JoinDispatchFragment.KEY_DESTINATION_LATITUDE,
                                query.getQuery().getDestinationLocation().getLat());
                        extras.putDouble(JoinDispatchFragment.KEY_DESTINATION_LONGITUDE,
                                query.getQuery().getDestinationLocation().getLng());
                        extras.putInt(JoinDispatchFragment.KEY_MAX_WAITING_TIME,
                                (int) query.getQuery().getMaxWaitingTimeInSeconds());

                        if (LifecycleHandler.isApplicationInForeground()) {
                            Intent startingIntent = new Intent(Constants.EVENT_CHANGE_JOIN_UI);
                            startingIntent.putExtras(extras);
                            LocalBroadcastManager.getInstance(getApplicationContext())
                                    .sendBroadcast(startingIntent);
                        } else {
                            // create notification for the user
                            Intent startingIntent = new Intent(getApplicationContext(), MainActivity.class);
                            startingIntent.putExtras(extras);
                            PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0,
                                    startingIntent, PendingIntent.FLAG_UPDATE_CURRENT);
                            createNotification(getString(R.string.found_matches_title),
                                    getString(R.string.found_matches_msg),
                                    GcmConstants.GCM_NOTIFICATION_FOUND_MATCHES_ID, contentIntent);
                        }
                    }
                }, new Action1<Throwable>() {
                    @Override
                    public void call(Throwable throwable) {
                        Timber.e("Something went wrong when downloading join request: " + throwable.getMessage());
                    }
                });
    }

    private void handleRequestDeclined(Intent intent) {
        Timber.d("REQUEST_DECLINED");

        // extract join request and offer from message
        long joinTripRequestId = Long.parseLong(intent.getExtras().getString(GcmConstants.GCM_MSG_JOIN_REQUEST_ID));
        long offerId = Long.parseLong(intent.getExtras().getString(GcmConstants.GCM_MSG_JOIN_REQUEST_OFFER_ID));

        // download the join trip request
        tripsResource.getJoinRequest(joinTripRequestId).observeOn(Schedulers.io())
                .subscribeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<JoinTripRequest>() {
                    @Override
                    public void call(JoinTripRequest joinTripRequest) {

                        //Check the two starting positions. If they are the same, this was the declined message from the first driver
                        RouteLocation r1 = joinTripRequest.getSuperTrip().getQuery().getStartLocation();
                        RouteLocation r2 = joinTripRequest.getSubQuery().getStartLocation();
                        boolean firstDriver = r1.equals(r2);

                        //save the canceled waiting status only if the first driver canceled
                        if (firstDriver) {
                            final SharedPreferences prefs = getApplicationContext().getSharedPreferences(
                                    Constants.SHARED_PREF_FILE_PREFERENCES, Context.MODE_PRIVATE);
                            SharedPreferences.Editor editor = prefs.edit();
                            editor.putBoolean(Constants.SHARED_PREF_KEY_SEARCHING, true);
                            editor.putBoolean(Constants.SHARED_PREF_KEY_WAITING, false);
                            editor.apply();

                            tripsResource.cancelSuperTrip(joinTripRequest.getSuperTrip().getId())
                                    .observeOn(Schedulers.io()).subscribeOn(AndroidSchedulers.mainThread())
                                    .subscribe(new Action1<SuperTrip>() {
                                        @Override
                                        public void call(SuperTrip superTrip) {
                                            Timber.d("Cancelled your super trip");
                                        }
                                    }, new Action1<Throwable>() {
                                        @Override
                                        public void call(Throwable throwable) {
                                            Timber.e("Could not cancel your trip: " + throwable.getMessage());
                                        }
                                    });

                        }

                        Bundle extras = new Bundle();
                        TripQuery query = joinTripRequest.getSuperTrip().getQuery();
                        extras.putDouble(JoinDispatchFragment.KEY_CURRENT_LOCATION_LATITUDE,
                                query.getStartLocation().getLat());
                        extras.putDouble(JoinDispatchFragment.KEY_CURRENT_LOCATION_LONGITUDE,
                                query.getStartLocation().getLng());
                        extras.putDouble(JoinDispatchFragment.KEY_DESTINATION_LATITUDE,
                                query.getDestinationLocation().getLat());
                        extras.putDouble(JoinDispatchFragment.KEY_DESTINATION_LONGITUDE,
                                query.getDestinationLocation().getLng());
                        extras.putInt(JoinDispatchFragment.KEY_MAX_WAITING_TIME,
                                (int) query.getMaxWaitingTimeInSeconds());

                        if (LifecycleHandler.isApplicationInForeground()) {
                            //go back to search UI only if the first driver canceled
                            if (firstDriver) {
                                //Toast.makeText(getApplicationContext(), getString(R.string.join_request_declined_msg), Toast.LENGTH_SHORT).show();
                                Intent startingIntent = new Intent(Constants.EVENT_CHANGE_JOIN_UI);
                                startingIntent.putExtras(extras);
                                LocalBroadcastManager.getInstance(getApplicationContext())
                                        .sendBroadcast(startingIntent);
                            } else {
                                Intent startingIntent = new Intent(Constants.EVENT_SECONDARY_DRIVER_DECLINED);
                                startingIntent.putExtras(extras);
                                LocalBroadcastManager.getInstance(getApplicationContext())
                                        .sendBroadcast(startingIntent);
                            }
                        } else {
                            // create notification for the user
                            Intent startingIntent = new Intent(getApplicationContext(), MainActivity.class);
                            startingIntent.putExtras(extras);
                            PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0,
                                    startingIntent, PendingIntent.FLAG_UPDATE_CURRENT);
                            createNotification(getString(R.string.join_request_declined_title),
                                    getString(R.string.join_request_declined_msg),
                                    GcmConstants.GCM_NOTIFICATION_REQUEST_DECLINED_ID, contentIntent);
                        }

                    }
                }, new Action1<Throwable>() {
                    @Override
                    public void call(Throwable throwable) {
                        Timber.e("Something went wrong when downloading join request: " + throwable.getMessage());
                    }
                });
    }

    private void handleRequestAccepted(Intent intent) {
        Timber.d("REQUEST_ACCEPTED");

        // extract join request and offer from message
        final long joinTripRequestId = Long
                .parseLong(intent.getExtras().getString(GcmConstants.GCM_MSG_JOIN_REQUEST_ID));
        long offerId = Long.parseLong(intent.getExtras().getString(GcmConstants.GCM_MSG_JOIN_REQUEST_OFFER_ID));

        // download the join trip request
        tripsResource.getJoinRequest(joinTripRequestId).observeOn(Schedulers.io())
                .subscribeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<JoinTripRequest>() {
                    @Override
                    public void call(JoinTripRequest joinTripRequest) {

                        //Check the two starting positions. If they are the same, this was the declined message from the first driver
                        RouteLocation r1 = joinTripRequest.getSuperTrip().getQuery().getStartLocation();
                        RouteLocation r2 = joinTripRequest.getSubQuery().getStartLocation();
                        boolean firstDriver = r1.equals(r2);

                        //save the accepted status only if the first driver accepted
                        if (firstDriver) {
                            final SharedPreferences prefs = getApplicationContext().getSharedPreferences(
                                    Constants.SHARED_PREF_FILE_PREFERENCES, Context.MODE_PRIVATE);
                            SharedPreferences.Editor editor = prefs.edit();
                            editor.putBoolean(Constants.SHARED_PREF_KEY_ACCEPTED, true);
                            editor.putBoolean(Constants.SHARED_PREF_KEY_WAITING, false);
                            editor.putBoolean(Constants.SHARED_PREF_KEY_SEARCHING, false);
                            editor.putLong(Constants.SHARED_PREF_KEY_TRIP_ID, joinTripRequest.getId());
                            editor.apply();
                        }

                        Bundle extras = new Bundle();
                        ObjectMapper mapper = new ObjectMapper();
                        try {
                            extras.putString(JoinDispatchFragment.KEY_JOIN_TRIP_REQUEST_RESULT,
                                    mapper.writeValueAsString(joinTripRequest));
                        } catch (JsonProcessingException e) {
                            Timber.e("Could not map join trip result");
                            e.printStackTrace();
                        }

                        if (LifecycleHandler.isApplicationInForeground()) {
                            if (firstDriver) {
                                Intent startingIntent = new Intent(Constants.EVENT_CHANGE_JOIN_UI);
                                startingIntent.putExtras(extras);
                                LocalBroadcastManager.getInstance(getApplicationContext())
                                        .sendBroadcast(startingIntent);
                            } else {
                                Intent startingIntent = new Intent(Constants.EVENT_SECONDARY_DRIVER_ACCEPTED);
                                startingIntent.putExtras(extras);
                                LocalBroadcastManager.getInstance(getApplicationContext())
                                        .sendBroadcast(startingIntent);
                            }
                        } else {
                            // create notification for the user only if the first driver accepts
                            Intent startingIntent = new Intent(getApplicationContext(), MainActivity.class);
                            startingIntent.putExtras(extras);
                            PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0,
                                    startingIntent, PendingIntent.FLAG_UPDATE_CURRENT);
                            createNotification(getString(R.string.join_request_accepted_title),
                                    getString(R.string.join_request_accepted_msg,
                                            joinTripRequest.getOffer().getDriver().getFirstName()),
                                    GcmConstants.GCM_NOTIFICATION_REQUEST_ACCEPTED_ID, contentIntent);
                        }
                    }
                }, new Action1<Throwable>() {
                    @Override
                    public void call(Throwable throwable) {
                        Timber.e("Something went wrong when downloading join request: " + throwable.getMessage());
                    }
                });
    }

    private void handleJoinRequest(Intent intent) {
        Timber.d("JOIN_REQUEST");

        if (LifecycleHandler.isApplicationInForeground()) {
            // Have screen update itself
            Intent startingIntent = new Intent(Constants.EVENT_NEW_JOIN_REQUEST);
            LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(startingIntent);

        } else {
            // Show notification
            // extract join request and offer from message
            long joinTripRequestId = Long
                    .parseLong(intent.getExtras().getString(GcmConstants.GCM_MSG_JOIN_REQUEST_ID));

            // download the join trip request
            tripsResource.getJoinRequest(joinTripRequestId).observeOn(Schedulers.io())
                    .subscribeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<JoinTripRequest>() {
                        @Override
                        public void call(JoinTripRequest joinTripRequest) {
                            // create notification for the user
                            Intent startingIntent = new Intent(getApplicationContext(), MainActivity.class);
                            startingIntent.setAction(MainActivity.ACTION_SHOW_JOIN_TRIP_REQUESTS);

                            PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0,
                                    startingIntent, PendingIntent.FLAG_UPDATE_CURRENT);
                            createNotification(getString(R.string.join_request_title),
                                    getString(R.string.joint_request_msg,
                                            joinTripRequest.getSuperTrip().getQuery().getPassenger()
                                                    .getFirstName()),
                                    GcmConstants.GCM_NOTIFICATION_JOIN_REQUEST_ID, contentIntent);
                        }
                    }, new Action1<Throwable>() {
                        @Override
                        public void call(Throwable throwable) {
                            Timber.e("Something went wrong when downloading join request: "
                                    + throwable.getMessage());
                        }
                    });
        }
    }

    private void handleTripCanceledByDriver() {

        if (LifecycleHandler.isApplicationInForeground()) {
            Timber.d("Trip Canceled by Driver");
        } else {
            //Create a notification for the passengers who already joined the trip
            Intent startingIntent = new Intent(getApplicationContext(), MainActivity.class);
            startingIntent.setAction(MainActivity.ACTION_SHOW_JOIN_TRIP_FRAGMENT);

            PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, startingIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            createNotification(getString(R.string.new_msg), getString(R.string.trip_canceled_msg),
                    GcmConstants.GCM_NOTIFICATION_TRIP_CANCELLED_ID, contentIntent);
        }
        //Change the status of Join trip flags
        final SharedPreferences prefs = getApplicationContext()
                .getSharedPreferences(Constants.SHARED_PREF_FILE_PREFERENCES, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putBoolean(Constants.SHARED_PREF_KEY_SEARCHING, false);
        editor.putBoolean(Constants.SHARED_PREF_KEY_ACCEPTED, false);
        editor.putLong(Constants.SHARED_PREF_KEY_QUERY_ID, -1);
        editor.apply();
    }

    private void handleTripCanceledByPassenger() {
        Timber.d("Trip Canceled by passenger");

        if (LifecycleHandler.isApplicationInForeground()) {
            // send broadcast while the app is running to reload the application
            Intent startingIntent = new Intent(Constants.EVENT_PASSENGER_CANCELLED_TRIP);
            LocalBroadcastManager.getInstance(this).sendBroadcast(startingIntent);
        } else {
            // create notification if the application is not in foreground
            Intent startingIntent = new Intent(getApplicationContext(), MainActivity.class);
            startingIntent.setAction(MainActivity.ACTION_SHOW_JOIN_TRIP_REQUESTS);

            PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, startingIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            createNotification(getString(R.string.new_msg), getString(R.string.trip_canceled_by_passenger),
                    GcmConstants.GCM_NOTIFICATION_TRIP_CANCELLED_ID, contentIntent);
        }

    }

    private void createNotification(String title, String message, int notificationId) {
        createNotification(title, message, notificationId, null);
    }

    private void createNotification(String title, String message, int notificationId, PendingIntent contentIntent) {
        NotificationManager notificationManager = (NotificationManager) this
                .getSystemService(Context.NOTIFICATION_SERVICE);

        Notification notification = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_directions_car_white).setContentTitle(title)
                .setStyle(new NotificationCompat.BigTextStyle().bigText(message)).setContentText(message)
                .setContentIntent(contentIntent).build();

        notification.flags |= Notification.FLAG_AUTO_CANCEL;

        notificationManager.notify(notificationId, notification);
    }

    public void handleJoinRequestExpired() {
        Timber.d("Request Expired");
        if (LifecycleHandler.isApplicationInForeground()) {
            Timber.d("Request Expired and Broadcast was sent to LocalBroadcastManager");
            Intent startingIntent = new Intent(Constants.EVENT_JOIN_REQUEST_EXPIRED);
            LocalBroadcastManager.getInstance(this).sendBroadcast(startingIntent);
        } else
            Timber.d(
                    "Request Expired but Broadcast was not sent to LocalBroadcastManager, application not in Foreground");
    }

}