package de.westnordost.streetcomplete;
import android.Manifest;
import android.animation.ObjectAnimator;
import android.app.FragmentManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.location.Location;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.annotation.AnyThread;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.mapzen.android.lost.api.LocationRequest;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
import de.westnordost.osmapi.common.errors.OsmAuthorizationException;
import de.westnordost.osmapi.common.errors.OsmConnectionException;
import de.westnordost.streetcomplete.about.AboutActivity;
import de.westnordost.streetcomplete.data.Quest;
import de.westnordost.streetcomplete.data.QuestAutoSyncer;
import de.westnordost.streetcomplete.data.QuestChangesUploadService;
import de.westnordost.streetcomplete.data.QuestController;
import de.westnordost.streetcomplete.data.download.QuestDownloadProgressListener;
import de.westnordost.streetcomplete.data.download.QuestDownloadService;
import de.westnordost.streetcomplete.data.QuestGroup;
import de.westnordost.streetcomplete.data.VisibleQuestListener;
import de.westnordost.streetcomplete.location.LocationRequestFragment;
import de.westnordost.streetcomplete.location.LocationUtil;
import de.westnordost.streetcomplete.location.SingleLocationRequest;
import de.westnordost.streetcomplete.oauth.OAuth;
import de.westnordost.streetcomplete.oauth.OAuthComponent;
import de.westnordost.streetcomplete.oauth.OAuthWebViewDialogFragment;
import de.westnordost.streetcomplete.quests.AbstractQuestAnswerFragment;
import de.westnordost.streetcomplete.quests.OsmQuestAnswerListener;
import de.westnordost.streetcomplete.quests.QuestAnswerComponent;
import de.westnordost.streetcomplete.settings.SettingsActivity;
import de.westnordost.streetcomplete.statistics.AnswersCounter;
import de.westnordost.streetcomplete.location.LocationState;
import de.westnordost.streetcomplete.location.LocationStateButton;
import de.westnordost.streetcomplete.tangram.MapFragment;
import de.westnordost.streetcomplete.tangram.QuestsMapFragment;
import de.westnordost.streetcomplete.tools.CrashReportExceptionHandler;
import de.westnordost.streetcomplete.util.SlippyMapMath;
import de.westnordost.streetcomplete.util.SphericalEarthMath;
import de.westnordost.osmapi.map.data.BoundingBox;
import de.westnordost.osmapi.map.data.Element;
import de.westnordost.osmapi.map.data.LatLon;
import de.westnordost.osmapi.map.data.OsmElement;
import de.westnordost.streetcomplete.view.dialogs.AlertDialogBuilder;
import oauth.signpost.OAuthConsumer;
import static android.location.LocationManager.PROVIDERS_CHANGED_ACTION;
import static de.westnordost.streetcomplete.location.LocationUtil.MODE_CHANGED;
public class MainActivity extends AppCompatActivity implements
OsmQuestAnswerListener, VisibleQuestListener, QuestsMapFragment.Listener, MapFragment.Listener,
OAuthWebViewDialogFragment.OAuthListener, OAuthComponent.Listener,
LocationRequestFragment.LocationRequestListener
{
@Inject CrashReportExceptionHandler crashReportExceptionHandler;
@Inject LocationRequestFragment locationRequestFragment;
@Inject QuestAutoSyncer questAutoSyncer;
@Inject QuestController questController;
@Inject SharedPreferences prefs;
@Inject PerApplicationStartPrefs perApplicationStartPrefs;
@Inject OAuthComponent oAuthComponent;
private QuestsMapFragment mapFragment;
private LocationStateButton trackingButton;
private SingleLocationRequest singleLocationRequest;
private Long clickedQuestId = null;
private QuestGroup clickedQuestGroup = null;
private ProgressBar progressBar;
private AnswersCounter answersCounter;
private boolean downloadServiceIsBound;
private QuestDownloadService.Interface downloadService;
private ServiceConnection downloadServiceConnection = new ServiceConnection()
{
public void onServiceConnected(ComponentName className, IBinder service)
{
downloadService = (QuestDownloadService.Interface) service;
downloadService.setProgressListener(downloadProgressListener);
downloadService.stopForeground();
}
public void onServiceDisconnected(ComponentName className)
{
downloadService = null;
}
};
private final BroadcastReceiver uploadChangesErrorReceiver = new BroadcastReceiver()
{
@Override public void onReceive(Context context, Intent intent)
{
Exception e = (Exception) intent.getSerializableExtra(QuestChangesUploadService.EXCEPTION);
if(intent.getBooleanExtra(QuestChangesUploadService.IS_AUTH_FAILED, false))
{
// delete secret in case it failed while already having a token -> token is invalid
OAuth.deleteConsumer(prefs);
requestOAuthorized();
}
else if(intent.getBooleanExtra(QuestChangesUploadService.IS_CONNECTION_ERROR, false))
{
// a 5xx error is not the fault of this app. Nothing we can do about it, so
// just notify the user
Toast.makeText(MainActivity.this, R.string.upload_server_error, Toast.LENGTH_LONG).show();
}
else if(intent.getBooleanExtra(QuestChangesUploadService.IS_VERSION_BANNED, false))
{
new AlertDialogBuilder(MainActivity.this)
.setMessage(R.string.version_banned_message)
.setPositiveButton(android.R.string.ok, null)
.show();
}
else if(e != null)// any other error
{
crashReportExceptionHandler.askUserToSendErrorReport(
MainActivity.this, R.string.upload_error, e);
}
}
};
private final BroadcastReceiver uploadChangesFinishedReceiver = new BroadcastReceiver()
{
@Override public void onReceive(Context context, Intent intent)
{
answersCounter.update();
}
};
private BroadcastReceiver locationAvailabilityReceiver = new BroadcastReceiver()
{
@Override public void onReceive(Context context, Intent intent)
{
updateLocationAvailability();
}
};
@Override protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Injector.instance.getApplicationComponent().inject(this);
crashReportExceptionHandler.askUserToSendCrashReportIfExists(this);
setContentView(R.layout.activity_main);
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
if(prefs.getBoolean(Prefs.KEEP_SCREEN_ON, false))
{
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
questController.onCreate();
answersCounter = (AnswersCounter) toolbar.findViewById(R.id.answersCounter);
oAuthComponent.setListener(this);
getSupportFragmentManager().beginTransaction()
.add(locationRequestFragment, LocationRequestFragment.class.getSimpleName())
.commit();
singleLocationRequest = new SingleLocationRequest(this);
progressBar = (ProgressBar) findViewById(R.id.download_progress);
progressBar.setMax(1000);
mapFragment = (QuestsMapFragment) getFragmentManager().findFragmentById(R.id.map_fragment);
mapFragment.getMapAsync(BuildConfig.MAPZEN_API_KEY != null ?
BuildConfig.MAPZEN_API_KEY :
new String(new char[]{118,101,99,116,111,114,45,116,105,108,101,115,45,102,75,85,99,117,65,74}));
trackingButton = (LocationStateButton) findViewById(R.id.gps_tracking);
trackingButton.setOnClickListener(new View.OnClickListener()
{
@Override public void onClick(View v)
{
if(trackingButton.getState().isEnabled())
{
boolean isFollowing = mapFragment.isFollowingPosition();
setIsFollowingPosition(!isFollowing);
}
else
{
locationRequestFragment.startRequest();
}
}
});
boolean isFollowing = perApplicationStartPrefs.get().getBoolean(Prefs.FOLLOW_POSITION, true);
trackingButton.setActivated(isFollowing);
ImageButton zoomInButton = (ImageButton) findViewById(R.id.zoom_in);
zoomInButton.setOnClickListener(new View.OnClickListener()
{
@Override public void onClick(View v)
{
mapFragment.zoomIn();
}
});
ImageButton zoomOutButton = (ImageButton) findViewById(R.id.zoom_out);
zoomOutButton.setOnClickListener(new View.OnClickListener()
{
@Override public void onClick(View v)
{
mapFragment.zoomOut();
}
});
}
@Override public void onStart()
{
super.onStart();
answersCounter.update();
String name = LocationUtil.isNewLocationApi() ? MODE_CHANGED : PROVIDERS_CHANGED_ACTION;
registerReceiver(locationAvailabilityReceiver, new IntentFilter(name));
LocalBroadcastManager localBroadcaster = LocalBroadcastManager.getInstance(this);
IntentFilter uploadChangesErrFilter = new IntentFilter(QuestChangesUploadService.ACTION_ERROR);
localBroadcaster.registerReceiver(uploadChangesErrorReceiver, uploadChangesErrFilter);
IntentFilter uploadChangesFinishedFilter = new IntentFilter(QuestChangesUploadService.ACTION_FINISHED);
localBroadcaster.registerReceiver(uploadChangesFinishedReceiver, uploadChangesFinishedFilter);
questController.onStart(this);
questAutoSyncer.onStart();
progressBar.setAlpha(0f);
downloadServiceIsBound = bindService(
new Intent(this, QuestDownloadService.class),
downloadServiceConnection, BIND_AUTO_CREATE);
if(!perApplicationStartPrefs.get().getBoolean(Prefs.HAS_ASKED_FOR_LOCATION, false))
{
locationRequestFragment.startRequest();
}
else if(ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
{
updateLocationAvailability();
}
}
@Override public void onResume()
{
super.onResume();
}
@Override public void onPause()
{
super.onPause();
}
@Override public void onStop()
{
super.onStop();
LocalBroadcastManager localBroadcaster = LocalBroadcastManager.getInstance(this);
localBroadcaster.unregisterReceiver(uploadChangesErrorReceiver);
localBroadcaster.unregisterReceiver(uploadChangesFinishedReceiver);
unregisterReceiver(locationAvailabilityReceiver);
questController.onStop();
questAutoSyncer.onStop();
perApplicationStartPrefs.get().putBoolean(Prefs.FOLLOW_POSITION, trackingButton.isActivated());
if (downloadServiceIsBound) unbindService(downloadServiceConnection);
if (downloadService != null)
{
downloadService.setProgressListener(null);
downloadService.startForeground();
// since we unbound from the service, we won't get the onFinished call. But we will get
// the onStarted call when we return to this activity when the service is rebound
progressBar.setAlpha(0f);
}
}
@Override public void onDestroy()
{
super.onDestroy();
questController.onDestroy();
}
@Override public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override public boolean onOptionsItemSelected(MenuItem item)
{
int id = item.getItemId();
switch (id)
{
case R.id.action_settings:
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
return true;
case R.id.action_about:
startActivity(new Intent(this, AboutActivity.class));
return true;
case R.id.action_download:
if(isConnected()) downloadDisplayedArea();
else Toast.makeText(this, R.string.offline, Toast.LENGTH_SHORT).show();
return true;
case R.id.action_upload:
if(isConnected()) uploadChanges();
else Toast.makeText(this, R.string.offline, Toast.LENGTH_SHORT).show();
return true;
}
return super.onOptionsItemSelected(item);
}
private void uploadChanges()
{
// because the app should ask for permission even if there is nothing to upload right now
if(!OAuth.isAuthorized(prefs))
{
requestOAuthorized();
}
else
{
questController.upload();
}
}
private void requestOAuthorized()
{
DialogInterface.OnClickListener onYes = new DialogInterface.OnClickListener()
{
@Override public void onClick(DialogInterface dialog, int which)
{
OAuthWebViewDialogFragment dlg = OAuthWebViewDialogFragment.create(
OAuth.createConsumer(), OAuth.createProvider());
dlg.show(getFragmentManager(), OAuthWebViewDialogFragment.TAG);
}
};
new AlertDialogBuilder(this)
.setMessage(R.string.confirmation_authorize_now)
.setPositiveButton(android.R.string.ok, onYes)
.setNegativeButton(R.string.later, null).show();
}
@Override public void onOAuthAuthorized(OAuthConsumer consumer, List<String> permissions)
{
oAuthComponent.onOAuthAuthorized(consumer, permissions);
}
@Override public void onOAuthCancelled()
{
oAuthComponent.onOAuthCancelled();
}
@Override public void onOAuthAuthorizationVerified()
{
answersCounter.update();
// now finally we can upload our changes!
questAutoSyncer.triggerAutoUpload();
}
private void downloadDisplayedArea()
{
BoundingBox displayArea;
if ((displayArea = mapFragment.getDisplayedArea()) == null)
{
Toast.makeText(this, R.string.cannot_find_bbox, Toast.LENGTH_LONG).show();
}
else
{
final BoundingBox enclosingBBox = SlippyMapMath.asBoundingBoxOfEnclosingTiles(
displayArea, ApplicationConstants.QUEST_TILE_ZOOM);
double areaInSqKm = SphericalEarthMath.enclosedArea(enclosingBBox) / 1000000;
if (areaInSqKm > ApplicationConstants.MAX_DOWNLOADABLE_AREA_IN_SQKM)
{
Toast.makeText(this, R.string.download_area_too_big, Toast.LENGTH_LONG).show();
}
else
{
if (questController.isPriorityDownloadRunning())
{
DialogInterface.OnClickListener onYes = new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
downloadAreaConfirmed(enclosingBBox);
}
};
new AlertDialogBuilder(this)
.setMessage(R.string.confirmation_cancel_prev_download_title)
.setPositiveButton(android.R.string.ok, onYes)
.setNegativeButton(android.R.string.cancel, null)
.show();
}
else
{
downloadAreaConfirmed(enclosingBBox);
}
}
}
}
private void downloadAreaConfirmed(BoundingBox bbox)
{
double areaInSqKm = SphericalEarthMath.enclosedArea(bbox) / 1000000;
// below a certain threshold, it does not make sense to download, so let's enlarge it
if (areaInSqKm < ApplicationConstants.MIN_DOWNLOADABLE_AREA_IN_SQKM)
{
LatLon pos = mapFragment.getPosition();
if (pos != null)
{
questController.download(SphericalEarthMath.enclosingBoundingBox(pos,
ApplicationConstants.MIN_DOWNLOADABLE_RADIUS_IN_METERS), null, true);
}
}
else
{
questController.download(bbox, null, true);
}
}
/* ------------------------------------ Progress bar --------------------------------------- */
private final QuestDownloadProgressListener downloadProgressListener
= new QuestDownloadProgressListener()
{
@Override public void onStarted()
{
runOnUiThread(new Runnable()
{
@Override public void run()
{
ObjectAnimator fadeInAnimator = ObjectAnimator.ofFloat(progressBar, View.ALPHA, 1f);
fadeInAnimator.start();
progressBar.setProgress(0);
Toast.makeText(
MainActivity.this,
R.string.now_downloading_toast,
Toast.LENGTH_SHORT).show();
}
});
}
@Override public void onProgress(final float progress)
{
runOnUiThread(new Runnable()
{
@Override public void run()
{
int intProgress = (int) (1000 * progress);
ObjectAnimator progressAnimator = ObjectAnimator.ofInt(progressBar, "progress", intProgress);
progressAnimator.setDuration(1000);
progressAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
progressAnimator.start();
}
});
}
@Override public void onError(final Exception e)
{
// a 5xx error is not the fault of this app. Nothing we can do about it, so it does not
// make sense to send an error report. Just notify the user
if(e instanceof OsmConnectionException)
{
Toast.makeText(MainActivity.this, R.string.download_server_error, Toast.LENGTH_LONG).show();
}
else
{
crashReportExceptionHandler.askUserToSendErrorReport(MainActivity.this, R.string.download_error, e);
}
}
@Override public void onSuccess()
{
// after downloading, regardless if triggered manually or automatically, the
// auto downloader should check whether there are enough quests in the vicinity now
questAutoSyncer.triggerAutoDownload();
}
@Override public void onFinished()
{
runOnUiThread(new Runnable()
{
@Override public void run()
{
ObjectAnimator fadeOutAnimator = ObjectAnimator.ofFloat(progressBar, View.ALPHA, 0f);
fadeOutAnimator.setDuration(1000);
fadeOutAnimator.start();
}
});
}
@Override public void onNotStarted()
{
if(downloadService.currentDownloadHasPriority())
{
Toast.makeText(MainActivity.this, R.string.nothing_more_to_download, Toast.LENGTH_SHORT).show();
}
}
};
/* ------------ Managing bottom sheet (quest details) and interaction with map ------------- */
private final static String BOTTOM_SHEET = "bottom_sheet";
@Override public void onBackPressed()
{
AbstractQuestAnswerFragment f = getQuestDetailsFragment();
if(f != null)
{
f.onClickClose(new Runnable()
{
@Override public void run()
{
mapFragment.removeQuestGeometry();
MainActivity.super.onBackPressed();
}
});
} else {
super.onBackPressed();
}
}
/* ------------- OsmQuestAnswerListener ------------- */
@Override public void onAnsweredQuest(long questId, QuestGroup group, Bundle answer)
{
closeQuestDetailsFor(questId, group);
answersCounter.answeredQuest();
questController.solveQuest(questId, group, answer);
}
@Override public void onLeaveNote(long questId, QuestGroup group, String note)
{
closeQuestDetailsFor(questId, group);
questController.createNote(questId, note);
}
@Override public void onSkippedQuest(long questId, QuestGroup group)
{
closeQuestDetailsFor(questId, group);
questController.hideQuest(questId, group);
}
private void closeQuestDetailsFor(long questId, QuestGroup group)
{
if (isQuestDetailsCurrentlyDisplayedFor(questId, group))
{
closeQuestDetails();
}
}
/* ------------- VisibleQuestListener ------------- */
@AnyThread
@Override public void onQuestsCreated(Collection<? extends Quest> quests, QuestGroup group)
{
mapFragment.addQuests(quests, group);
// to recreate element geometry of selected quest (if any) after recreation of activity
if(getQuestDetailsFragment() != null)
{
for (Quest q : quests)
{
if (isQuestDetailsCurrentlyDisplayedFor(q.getId(), group))
{
questController.retrieve(group, q.getId());
return;
}
}
}
}
@AnyThread
@Override public synchronized void onQuestCreated(final Quest quest, final QuestGroup group,
final Element element)
{
if (clickedQuestId != null && quest.getId().equals(clickedQuestId) && group == clickedQuestGroup)
{
runOnUiThread(new Runnable()
{
@Override public void run()
{
requestShowQuestDetails(quest, group, element);
}
});
clickedQuestId = null;
clickedQuestGroup = null;
} else if (isQuestDetailsCurrentlyDisplayedFor(quest.getId(), group))
{
mapFragment.addQuestGeometry(quest.getGeometry());
}
}
@AnyThread
@Override public synchronized void onQuestsRemoved(Collection<Long> questIds, QuestGroup group)
{
removeQuests(questIds, group);
}
@AnyThread
@Override public synchronized void onQuestSolved(long questId, QuestGroup group)
{
questAutoSyncer.triggerAutoUpload();
removeQuests(Collections.singletonList(questId), group);
}
private void removeQuests(Collection<Long> questIds, QuestGroup group)
{
// amount of quests is reduced -> check if redownloding now makes sense
questAutoSyncer.triggerAutoDownload();
for(long questId : questIds)
{
if (!isQuestDetailsCurrentlyDisplayedFor(questId, group)) continue;
runOnUiThread(new Runnable() { @Override public void run() { closeQuestDetails(); }});
break;
}
mapFragment.removeQuests(questIds, group);
}
@UiThread private void closeQuestDetails()
{
getFragmentManager().popBackStack(BOTTOM_SHEET, FragmentManager.POP_BACK_STACK_INCLUSIVE);
mapFragment.removeQuestGeometry();
// sometimes the keyboard fails to close
View view = this.getCurrentFocus();
if (view != null)
{
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
private boolean isQuestDetailsCurrentlyDisplayedFor(long questId, QuestGroup group)
{
AbstractQuestAnswerFragment currentFragment = getQuestDetailsFragment();
return currentFragment != null
&& currentFragment.getQuestId() == questId
&& currentFragment.getQuestGroup() == group;
}
@UiThread private void requestShowQuestDetails(final Quest quest, final QuestGroup group,
final Element element)
{
if (isQuestDetailsCurrentlyDisplayedFor(quest.getId(), group)) return;
AbstractQuestAnswerFragment f = getQuestDetailsFragment();
if (f != null)
{
f.onClickClose(new Runnable()
{
@Override public void run()
{
showQuestDetails(quest, group, element);
}
});
} else {
showQuestDetails(quest, group, element);
}
}
@UiThread private void showQuestDetails(final Quest quest, final QuestGroup group,
final Element element)
{
if(getQuestDetailsFragment() != null)
{
closeQuestDetails();
}
mapFragment.addQuestGeometry(quest.getGeometry());
AbstractQuestAnswerFragment f = quest.getType().createForm();
Bundle args = QuestAnswerComponent.createArguments(quest.getId(), group);
if (group == QuestGroup.OSM)
{
args.putSerializable(AbstractQuestAnswerFragment.ELEMENT, (OsmElement) element);
}
f.setArguments(args);
android.app.FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(
R.animator.enter_from_bottom, R.animator.exit_to_bottom,
R.animator.enter_from_bottom, R.animator.exit_to_bottom);
ft.add(R.id.map_bottom_sheet_container, f, BOTTOM_SHEET);
ft.addToBackStack(BOTTOM_SHEET);
ft.commit();
}
private AbstractQuestAnswerFragment getQuestDetailsFragment()
{
return (AbstractQuestAnswerFragment) getFragmentManager().findFragmentByTag(BOTTOM_SHEET);
}
/* ---------- QuestsMapFragment.Listener ---------- */
@Override public void onMapReady()
{
}
@Override public void onFirstInView(BoundingBox bbox)
{
questController.retrieve(bbox);
}
@Override public void onUnglueViewFromPosition()
{
trackingButton.setActivated(false);
}
@Override public void onClickedQuest(QuestGroup questGroup, Long questId)
{
clickedQuestId = questId;
clickedQuestGroup = questGroup;
questController.retrieve(questGroup, questId);
}
@Override public void onClickedMapAt(@Nullable LatLon position)
{
AbstractQuestAnswerFragment f = getQuestDetailsFragment();
if(f != null)
{
f.onClickClose(new Runnable()
{
@Override public void run()
{
mapFragment.removeQuestGeometry();
closeQuestDetails();
}
});
}
}
/* ---------- Location listener ---------- */
private void updateLocationAvailability()
{
if(LocationUtil.isLocationSettingsOn(this))
{
onLocationIsEnabled();
}
else
{
onLocationIsDisabled();
}
}
private void onLocationIsEnabled()
{
trackingButton.setState(LocationState.SEARCHING);
mapFragment.setIsFollowingPosition(trackingButton.isActivated());
mapFragment.startPositionTracking();
questAutoSyncer.startPositionTracking();
singleLocationRequest.startRequest(LocationRequest.PRIORITY_HIGH_ACCURACY,
new SingleLocationRequest.Callback()
{
@Override public void onLocation(Location location)
{
trackingButton.setState(LocationState.UPDATING);
}
});
}
private void onLocationIsDisabled()
{
trackingButton.setState(LocationState.ALLOWED);
setIsFollowingPosition(false);
mapFragment.stopPositionTracking();
questAutoSyncer.stopPositionTracking();
singleLocationRequest.stopRequest();
}
private void setIsFollowingPosition(boolean follow)
{
trackingButton.setActivated(follow);
mapFragment.setIsFollowingPosition(follow);
}
@Override public void onLocationRequestFinished(LocationState withLocationState)
{
perApplicationStartPrefs.get().putBoolean(Prefs.HAS_ASKED_FOR_LOCATION, true);
trackingButton.setState(withLocationState);
boolean enabled = withLocationState.isEnabled();
if(enabled)
{
onLocationIsEnabled();
}
else
{
Toast.makeText(MainActivity.this, R.string.no_gps_no_quests, Toast.LENGTH_LONG).show();
}
}
// ---------------------------------------------------------------------------------------------
/** Does not necessarily mean that the user has internet. But if he is not connected, he will
* not have internet */
private boolean isConnected()
{
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
}