/*
* 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.activities;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.location.Location;
import android.location.LocationManager;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckBox;
import com.google.android.gms.location.LocationRequest;
import org.croudtrip.Constants;
import org.croudtrip.R;
import org.croudtrip.account.AccountManager;
import org.croudtrip.api.TripsResource;
import org.croudtrip.api.account.User;
import org.croudtrip.fragments.ProfileFragment;
import org.croudtrip.fragments.SettingsFragment;
import org.croudtrip.fragments.join.JoinDispatchFragment;
import org.croudtrip.fragments.offer.DispatchOfferTripFragment;
import org.croudtrip.gcm.GcmManager;
import org.croudtrip.location.LocationUpdater;
import org.croudtrip.location.LocationUploadTimerReceiver;
import org.croudtrip.utils.CrashCallback;
import org.croudtrip.utils.DefaultTransformer;
import java.io.InputStream;
import java.net.URL;
import javax.inject.Inject;
import javax.net.ssl.HttpsURLConnection;
import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer;
import it.neokree.materialnavigationdrawer.elements.MaterialAccount;
import it.neokree.materialnavigationdrawer.elements.MaterialSection;
import pl.charmas.android.reactivelocation.ReactiveLocationProvider;
import rx.Observable;
import rx.Subscription;
import rx.functions.Action1;
import rx.functions.Func0;
import rx.subscriptions.CompositeSubscription;
import timber.log.Timber;
/**
* We will probably use fragments, so this activity works as a container for all these fragments and will probably do
* some initialization and stuff
*/
public class MainActivity extends AbstractRoboDrawerActivity {
//******************************** Variables ***********************************//
// If a notification arrives this sometimes has to change the displayed screen.
// These constants are used to determine which screen should be shown.
public final static String ACTION_SHOW_JOIN_TRIP_REQUESTS = "SHOW_JOIN_TRIP_REQUESTS";
public final static String ACTION_SHOW_REQUEST_ACCEPTED = "SHOW_REQUEST_ACCEPTED";
public final static String ACTION_SHOW_REQUEST_DECLINED = "SHOW_REQUEST_DECLINED";
public final static String ACTION_SHOW_FOUND_MATCHES = "SHOW_FOUND_MATCHES";
public final static String ACTION_SHOW_JOIN_TRIP_FRAGMENT = "SHOW_JOIN_TRIP_FRAGMENT";
@Inject private GcmManager gcmManager;
@Inject private LocationUpdater locationUpdater;
@Inject private TripsResource tripsResource;
private CompositeSubscription subscriptions = new CompositeSubscription();
private Subscription locationUpdateSubscription;
//********************************* Methods ************************************//
@Override
protected void onNewIntent(Intent intent){
if (intent.getAction() != null && intent.getAction().equals(NfcAdapter.ACTION_TAG_DISCOVERED)) {
//user scanned an NFC tag -> notify the passenger driving UI to save new status and maybe update UI
Intent startingIntent = new Intent(Constants.EVENT_NFC_TAG_SCANNED);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(startingIntent);
} else {
Timber.d("Another Intent or detected some other NFC stuff...");
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void init(Bundle savedInstanceState) {
// Configure Navigation Drawer
this.disableLearningPattern();
this.allowArrowAnimation();
this.setBackPattern(MaterialNavigationDrawer.BACKPATTERN_BACK_TO_FIRST);
this.setDrawerHeaderImage(R.drawable.background_drawer);
// Get all the saved user data to display some info in the navigation drawer
showUserInfoInNavigationDrawer();
SharedPreferences prefs = getSharedPreferences(Constants.SHARED_PREF_FILE_PREFERENCES,
Context.MODE_PRIVATE);
// Start timer to update the user's offers all the time
if( AccountManager.isUserLoggedIn( this ) ){
Intent alarmIntent = new Intent(this, LocationUploadTimerReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
alarmManager.setRepeating( AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
120 * 1000, pendingIntent );
}
// Subscribe to location updates
LocationRequest request = LocationRequest.create() //standard GMS LocationRequest
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(10000);
ReactiveLocationProvider locationProvider = new ReactiveLocationProvider(this);
Subscription locationUpdateSubscription = locationProvider.getUpdatedLocation(request)
.subscribe(new Action1<Location>() {
@Override
public void call(Location location) {
locationUpdater.setLastLocation( location );
}
});
subscriptions.add(locationUpdateSubscription);
// GPS availability
if (!GPSavailable()) {
checkForGPS();
}
// Registration for GCM, if we are not registered yet
if( !gcmManager.isRegistered() ) {
Subscription subscription = gcmManager.register()
.compose(new DefaultTransformer<Void>())
.retry(3)
.subscribe( new Action1<Void>() {
@Override
public void call(Void aVoid) {
Timber.d("Registered at GCM.");
}
}, new CrashCallback(this, "failed to register for GCM"));
subscriptions.add(subscription);
}
fillNavigationDrawer();
}
@Override
public void onBackPressed() {
if (getCurrentSection().getTargetFragment() instanceof JoinDispatchFragment) {
JoinDispatchFragment currentFragment = (JoinDispatchFragment) getCurrentSection().getTargetFragment();
if (!currentFragment.allowBackPressed()) {
return;
}
}
super.onBackPressed();
}
@Override
public void onPause() {
super.onPause();
subscriptions.unsubscribe();
subscriptions.clear();
}
@Override
public void onStop() {
super.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
}
private boolean GPSavailable() {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
}
private void checkForGPS() {
final SharedPreferences prefs = getSharedPreferences(Constants.SHARED_PREF_FILE_PREFERENCES, Context.MODE_PRIVATE);
final SharedPreferences.Editor editor = prefs.edit();
AlertDialog.Builder adb = new AlertDialog.Builder(this);
LayoutInflater adbInflater = LayoutInflater.from(this);
View dialogLayout = adbInflater.inflate(R.layout.dialog_enable_gps, null);
final CheckBox dontShowAgain = (CheckBox) dialogLayout.findViewById(R.id.skip);
adb.setView(dialogLayout);
adb.setTitle(getResources().getString(R.string.enable_gps_title));
adb.setMessage(getResources().getString(R.string.enable_gps_description));
adb.setPositiveButton(getResources().getString(R.string.enable_gps_ok), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (dontShowAgain.isChecked()) {
editor.putBoolean(Constants.SHARED_PREF_KEY_SKIP_ENABLE_GPS, true);
editor.apply();
}
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
return;
}
});
adb.setNegativeButton(getResources().getString(R.string.enable_gps_cancel), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
return;
}
});
adb.show();
}
public void showUserInfoInNavigationDrawer(){
// Get logged-in user and his data
User user = AccountManager.getLoggedInUser(getApplicationContext());
String firstName = (user == null || user.getFirstName() == null) ? "" : user.getFirstName();
String lastName = (user == null || user.getLastName() == null) ? "" : user.getLastName();
String email = (user == null || user.getEmail() == null) ? "" : user.getEmail();
final String avatarUrl = (user == null || user.getAvatarUrl() == null) ? null : user.getAvatarUrl();
Timber.i("Nav drawer avatarUrl is: " + avatarUrl);
final MaterialAccount account = new MaterialAccount(this.getResources(),
firstName+ " " + lastName, email, R.drawable.profile, R.drawable.background_drawer);
this.addAccount(account);
// Download his avatar
if (avatarUrl != null) {
Observable.defer(new Func0<Observable<Bitmap>>() {
@Override
public Observable<Bitmap> call() {
try {
URL url = new URL(avatarUrl);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
return Observable.just(BitmapFactory.decodeStream(input));
} catch (Exception e) {
return Observable.error(e);
}
}
}).compose(new DefaultTransformer<Bitmap>())
.subscribe(new Action1<Bitmap>() {
@Override
public void call(Bitmap avatar) {
Timber.d("avatar is null " + (avatar == null));
Timber.d("" + avatar.getWidth());
account.setPhoto(avatar);
notifyAccountDataChanged();
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
Timber.e(throwable, "failed to download avatar");
}
});
}
}
private void fillNavigationDrawer(){
// Check the action that was given to the activity to determine the sections that
// should be shown
Intent intent = getIntent();
String action = intent.getAction();
action = (action == null) ? "" : action;
// (0) JOIN TRIP
JoinDispatchFragment joinDispatchFragment = new JoinDispatchFragment();
joinDispatchFragment.setArguments(getIntent().getExtras());
this.addSection(newSection(getString(R.string.menu_join_trip),
R.drawable.hitchhiker,
joinDispatchFragment));
// (1) OFFER TRIP
String offerName = getString(R.string.menu_offer_trip);
SharedPreferences prefs = getSharedPreferences(Constants.SHARED_PREF_FILE_PREFERENCES, MODE_PRIVATE);
if(prefs.getBoolean(Constants.SHARED_PREF_KEY_RUNNING_TRIP_OFFER, false)){
offerName = getString(R.string.menu_my_trip);
}
DispatchOfferTripFragment dispatchOfferTripFragment = new DispatchOfferTripFragment();
dispatchOfferTripFragment.setArguments(getIntent().getExtras());
this.addSection(newSection(offerName,
R.drawable.ic_directions_car_white,
dispatchOfferTripFragment));
// (2) PROFILE
if(AccountManager.isUserLoggedIn(this)) {
// Only logged-in users can view their profile
this.addSection(newSection(getString(R.string.menu_profile),
R.drawable.ic_person_black_36dp,
new ProfileFragment()));
}
// (3) SETTINGS
this.addBottomSection(newSection(getString(R.string.menu_settings),
R.drawable.ic_settings,
new SettingsFragment()));
// Set the section that should be loaded at the start of the application
if( action.equalsIgnoreCase(ACTION_SHOW_REQUEST_DECLINED) || action.equals(ACTION_SHOW_FOUND_MATCHES) ) {
this.setDefaultSectionLoaded(0);
MaterialSection section = this.getSectionByTitle(getString(R.string.menu_my_trip));
Bundle extras = getIntent().getExtras();
Bundle bundle = new Bundle();
bundle.putAll(extras);
Fragment requestFrag = (Fragment) section.getTargetFragment();
requestFrag.setArguments(bundle);
}else if( action.equalsIgnoreCase(ACTION_SHOW_JOIN_TRIP_REQUESTS) ) {
this.setDefaultSectionLoaded(1); // Offer trip (My trip)
}
else if (action.equalsIgnoreCase(ACTION_SHOW_JOIN_TRIP_FRAGMENT)) {
this.setDefaultSectionLoaded(0); //Join trip
}
}
}