I have an android service and I'd like to do the following:
When clicking a button, I start this service, the toast in the onCreate() method always appears but after that I cannot see the longitude-latitude popping up. My main goal is to use this longitude-latitude couple in more activities.
How can I achieve this?
I implemented GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location .LocationListener because I had to wait 20-30 seconds to get the coordinates. The following code works in an activity, but not as a service.
Thanks!
EDITED:
package com.si.ou;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
public class FullAutoService extends Service implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, com.google.android.gms.location
.LocationListener {
private static final int PERMISSION_REQUEST_ACCESS_FINE_LOCATION = 100;
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
String loki;
#Override
public void onCreate() {
createLocationRequest();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
Toast.makeText(this, "service started....", Toast.LENGTH_SHORT).show();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void startLocationUpdates() {
//noinspection MissingPermission
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission
.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat
.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
}
private void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
private boolean checkPermissions() {
return ContextCompat.checkSelfPermission(this, android.Manifest.permission
.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
private void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
#Override
public void onConnected(#Nullable Bundle bundle) {
if (checkPermissions() && mGoogleApiClient.isConnected()) startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
#Override
public void onLocationChanged(Location location) {
Double lati = location.getLatitude();
Double longi = location.getLongitude();
loki = String.valueOf(lati) + ":" + String.valueOf(longi);
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), loki, Toast.LENGTH_SHORT).show();
}
});
}
}
It is because you are working on Service.
Try this:
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(),
getString(R.string.string_id),
Toast.LENGTH_SHORT).show();
}
});
Any UI component can't be accessed from background thread.
If need be arise use handler and sen msg to UI thread and update UI components.
Related
I'm new to android and i'm trying to develop an android application which includes tracking the user location details and showing it on a google map and the location should be updated in the map whenever it is changed. I'm unable to understand how to get this through google maps v2. They mentioned to change dependencies but i'm unable to find where to do that can anyone explain the usage of this with a simple example i tried to implement the steps given in below link but i'm unable to find project properties to edit
https://docs.google.com/document/pub?id=19nQzvKP-CVLd7_VrpwnHfl-AE9fjbJySowONZZtNHzw
If you want to show location of user on map when the change their location you need to take, Location API and Google Map API,
here is dependency link put in your app level gradel,
dependencies {
compile 'com.google.android.gms:play-services-maps:10.0.1'
compile 'com.google.android.gms:play-services:10.0.1'
}
Then after you need to start location service for update location on map also you need to initialise your map,
Here i consider You initialised your map show I am just showing how to use location api,
import android.*;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.model.LatLng;
public class MainLocationActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, LocationListener, GoogleApiClient.OnConnectionFailedListener {
private static final float DISTANCE_FOR_FISPLACEMENT = 2; //here is the distance for update map in meter
private Context context;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context=this;
if (checkPermsion(context)) {
setupLocationService(context);
}
}
public boolean checkPermsion(Context context) {
int MyVersion = Build.VERSION.SDK_INT;
if (MyVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return false;
} else if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return false;
} else {
return true;
}
} else {
return true;
}
}
private void setupLocationService(Context context) {
if (checkPlayServices()) {
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
// .addApi(ActivityRecognition.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
createLocationRequest();
}
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest().create()
.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
.setFastestInterval(5 * 60 * 1000)
.setInterval(5 * 60 * 1000)
.setSmallestDisplacement(DISTANCE_FOR_FISPLACEMENT);
mGoogleApiClient.connect();
}
private boolean checkPlayServices() {
GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
int result = googleAPI.isGooglePlayServicesAvailable(this);
if (result != ConnectionResult.SUCCESS) {
return false;
}
return true;
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.i(TAG, "Connected to onConnected");
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
}
private void startLocationUpdates() {
if (mGoogleApiClient.isConnected()) {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
}
#Override
public void onLocationChanged(Location location) {
mMap.animateCamera(CameraUpdateFactory.newLatLng(new LatLng(location.getLatitude(), location.getLongitude())));
// Also here you can change your pin in map
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
}
Level
I am a beginner
Task
To run an android service that sends location updates (latitude, longitude) to a database periodically while a driver is driving (to track location) every 5mins. I want to update the database with location even if the app is not active, hence I decided to use the firebase job dispatcher.
Note
I have already seen several threads on how to do this using ALARM_MANAGER or broadcast receivers etc. I would like to know how to do this with a job dispatcher. My current code works but I am pretty sure its not the right way to go about it.
Questions
1. Where do I make a call to build the Googleapi and call the Connect() method? Right now, my scheduler calls a class 'onStart', which in turns performs the connection.
Instead of using the jobScheduler is there any way in which I can use the 'Location Receiver' to do this as I read it takes a time interval, and returns the updated location by overwriting onLocationChanged().
Currently Working Code
The firebase service:-
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import com.firebase.jobdispatcher.JobParameters;
import com.firebase.jobdispatcher.JobService;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationServices;
public class GPSTracking extends JobService {
private AsyncTask mBackgroundTask;
public static final String LOG_TAG = "location-scheduler";
#Override
public boolean onStartJob(final JobParameters jobParameters) {
Log.i(LOG_TAG,"Scheduling");
mBackgroundTask = new AsyncTask() {
#Override
protected Object doInBackground(Object[] params) {
Context context = GPSTracking2.this;
LocationTracker.execute(context);
return null;
}
#Override
protected void onPostExecute(Object o) {
jobFinished(jobParameters, false);
}
};
mBackgroundTask.execute();
return true;
}
#Override
public boolean onStopJob(JobParameters jobParameters) {
if (mBackgroundTask != null) {
mBackgroundTask.cancel(true);
}
return true;
}
}
The actual tracking:-
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationServices;
public class LocationTracker implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
private Location mLastLocation;
private Context context;
private static final String LOG_TAG="LOCATION TRACKER";
public LocationTracker(Context context){
this.context = context;
buildGoogleApiClient();
}
#Override
protected void finalize() throws Throwable {
super.finalize();
//Disconnect
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
public static void execute(Context context){
LocationTracker2 track = new LocationTracker2(context);
//connect
track.startConnection();
}
public void startConnection(){
mGoogleApiClient.connect();
}
private static void trackLocation(Location location) {
// To replace with updating database
if (location!=null) {
Log.i("TRACKING LAT", String.valueOf(location.getLatitude()));
Log.i("TRACKING LON", String.valueOf(location.getLongitude()));
}
else
{
Log.i("TRACKING LAT", "Null location received");
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
// Create new location request
// The permission should be granted previously
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
trackLocation(mLastLocation);
}
#Override
public void onConnectionSuspended(int i) {
Log.i(LOG_TAG,"Connection suspended");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.i(LOG_TAG,"Connection failed");
}
}
Inside Main, start the scheduling:
Driver driver = new GooglePlayDriver(context);
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(driver);
Job locationTrackerJob = dispatcher.newJobBuilder()
.setService(GPSTracking.class)
.setTag(JOB_TAG)
.setLifetime(Lifetime.FOREVER)
.setRecurring(true)
.setTrigger(Trigger.executionWindow(
REMINDER_INTERVAL_SECONDS,
REMINDER_INTERVAL_SECONDS + SYNC_FLEXTIME_SECONDS
))
.setReplaceCurrent(true)
.build();
dispatcher.schedule(locationTrackerJob);
NOTE
- You might have to add code to check for permissions depending on the api
- I am leaving out registering the service in Android manifest and dependency in build gradle.
So, I have custom Location Service class, from which I want to get last known location. It's possible, that I can call getLastKnownLocation() before GoogleApiClient is connected, so I have to wait for it and then call getLastKnownLocation(), but I have no clue how to manage that. I'm thinking that RxJava 2 can help me with that, but I'm not familiar with that framework yet. This is my class for now:
import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.model.LatLng;
import javax.inject.Inject;
import pl.pancor.android.air.base.FragmentScope;
#FragmentScope
public class LocationService implements Location.Service,
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
ActivityCompat.OnRequestPermissionsResultCallback {
private static final String TAG = LocationService.class.getSimpleName();
private static final int PERMISSIONS_REQUEST = 13;
private GoogleApiClient mGoogleApiClient;
private Activity mActivity;
private android.location.Location mLastLocation;
private Location.Receiver mReceiver;
#Inject
LocationService(Activity activity) {
mActivity = activity;
}
#Override
public void getLastKnownLocation() {
if (isPermissionsGranted(true))
getLocation();
}
/**
* #param request if permissions aren't granted and {#param request} is true,
* then request permissions
* #return true if location permissions are granted
*/
private boolean isPermissionsGranted(boolean request) {
if (ActivityCompat.checkSelfPermission(mActivity,
Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(mActivity,
Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {
if (request) {
ActivityCompat.requestPermissions(mActivity,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION},
PERMISSIONS_REQUEST);
}
return false;
}
return true;
}
private void getLocation() {
if (mGoogleApiClient != null)
mLastLocation = LocationServices.FusedLocationApi
.getLastLocation(mGoogleApiClient);
if (mLastLocation != null) {
LatLng latLng = new LatLng(mLastLocation.getLatitude(),
mLastLocation.getLongitude());
mReceiver.lastKnownLocation(latLng);
} else {
Log.e(TAG, "NULLLLLLLLLLLLLLLLLLLLLLL");
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
#Override
public void setupReceiver(Location.Receiver receiver) {
mReceiver = receiver;
}
#Override
public void onStart() {
if (mGoogleApiClient != null){
mGoogleApiClient.connect();
} else {
mGoogleApiClient = getGoogleApiClient();
mGoogleApiClient.connect();
}
}
#Override
public void onStop() {
if (mGoogleApiClient != null)
mGoogleApiClient.disconnect();
}
private GoogleApiClient getGoogleApiClient(){
return new GoogleApiClient.Builder(mActivity)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
switch (requestCode){
case PERMISSIONS_REQUEST:
if (grantResults.length > 0 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED){
getLastKnownLocation();
} else {
}
}
}
}
I need somehow to check if mGoogleApiClient is connected (mGoogleApiClient.isConnected()) and if not, wait to connect, and then get location from FusedLocationApi, but I don't want to put methods to onConnected(), because it will sometimes return location, when I don't want to return location.
After your explanations in the comment section, I would do something like this:
in the Receiver/Fragment class I would put some logic that sets a variable "updateUI" to true in the LocationService class, when it is appropriate for onConnected to call the mReceiver.lastKnownLocation(latLng)
method. The default value will be false, and if onConnected gets called before the receiver is ready, the method mReceiver.lastKnownLocation(latLng)
won't be called.
Another approach is to store always the last known location in your SharedPreferences (or at least in the onPause method). Then, you can always use it the first time you need a location and wait for more precise location later, but this method won't be so precise at start time.
So, after some time, i manage to make it and also finished my entire class and i would like to share with you, what i did
public interface Location {
interface Service extends BaseLocation<Receiver>{
void onStart();
void onStop();
void onActivityResult(int requestCode, int resultCode);
void getLastKnownLocation();
}
interface Receiver{
void lastKnownLocation(double latitude, double longitude);
void userRefusedToSendLocation();
void unableToObtainLocation();
}
}
import android.Manifest;
import android.app.Activity;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
import com.google.android.gms.location.LocationSettingsStatusCodes;
import javax.inject.Inject;
import pl.pancor.android.air.base.FragmentScope;
#FragmentScope
public class LocationService implements Location.Service,
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
ActivityCompat.OnRequestPermissionsResultCallback, LocationListener,
ResultCallback<LocationSettingsResult>{
private static final int PERMISSIONS_REQUEST = 13;
private static final int SETTINGS_CHECK = 23;
private static final int GOOGLE_API_CLIENT_ERROR = 33;
private static final int LOCATION_EXPIRATION_TIME = 10 * 1000;
private static final int LOCATION_INTERVAL = 2 * 1000;
private GoogleApiClient mGoogleApiClient;
private Activity mActivity;
private LocationRequest mLocationRequest;
private android.location.Location mLastLocation;
private Location.Receiver mReceiver;
private Handler mHandler;
private final Runnable mExpiredLocationUpdate = new Runnable() {
#Override
public void run() {
mReceiver.unableToObtainLocation();
}
};
private boolean isWaitingForConnect = false;
#Inject
LocationService(Activity activity) {
mActivity = activity;
}
#Override
public void getLastKnownLocation() {
if (isPermissionsGranted(true))
checkLocationSettings();
}
#Override
public void onActivityResult(int requestCode, int resultCode) {
resolveProblems(requestCode, resultCode);
}
#Override
public void onLocationChanged(android.location.Location location) {
if (mLastLocation == null) {
mLastLocation = location;
sendLatLngToReceiver();
}
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mHandler.removeCallbacks(mExpiredLocationUpdate);
}
#Override
public void onConnected(#Nullable Bundle bundle) {
if (isWaitingForConnect)
getLastKnownLocation();
}
#Override
public void onConnectionSuspended(int i) {
//mGoogleApiClient will automatically try to reconnect
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult result) {
if (!result.hasResolution()){
mReceiver.unableToObtainLocation();
GoogleApiAvailability.getInstance()
.getErrorDialog(mActivity, result.getErrorCode(), 0).show();
return;
}
if (mActivity.hasWindowFocus()) {
try {
result.startResolutionForResult(mActivity, GOOGLE_API_CLIENT_ERROR);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
}
#Override
public void setupReceiver(Location.Receiver receiver) {
mReceiver = receiver;
}
#Override
public void onStart() {
mHandler = new Handler();
if (mGoogleApiClient != null){
mGoogleApiClient.connect();
} else {
mGoogleApiClient = getGoogleApiClient();
mGoogleApiClient.connect();
}
}
#Override
public void onStop() {
if (mGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
mHandler.removeCallbacks(mExpiredLocationUpdate);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
switch (requestCode){
case PERMISSIONS_REQUEST:
if (grantResults.length > 0 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED){
getLastKnownLocation();
} else {
mReceiver.userRefusedToSendLocation();
}
}
}
#Override
public void onResult(#NonNull LocationSettingsResult result) {
final Status status = result.getStatus();
switch (status.getStatusCode()){
case LocationSettingsStatusCodes.SUCCESS:
getLocation();
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
if (mActivity.hasWindowFocus()) {
try {
status.startResolutionForResult(mActivity, SETTINGS_CHECK);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
mReceiver.unableToObtainLocation();
break;
}
}
private void checkLocationSettings() {
if (mGoogleApiClient != null){
mLocationRequest = new LocationRequest()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setFastestInterval(LOCATION_INTERVAL / 2)
.setInterval(LOCATION_INTERVAL)
.setNumUpdates(1);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
PendingResult<LocationSettingsResult> result = LocationServices
.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
result.setResultCallback(this);
}
}
private void getLocation(){
if (mGoogleApiClient != null)
mLastLocation = LocationServices.FusedLocationApi
.getLastLocation(mGoogleApiClient);
sendLatLngToReceiver();
}
private void sendLatLngToReceiver(){
if (mLastLocation != null) {
mReceiver.lastKnownLocation(mLastLocation.getLatitude(),
mLastLocation.getLongitude());
mHandler.removeCallbacks(mExpiredLocationUpdate);
} else {
requestLocation();
}
}
private void requestLocation(){
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
mHandler.postDelayed(mExpiredLocationUpdate, LOCATION_EXPIRATION_TIME);
} else {
isWaitingForConnect = true;
}
}
/**
* #param request if permissions aren't granted and {#param request} is true,
* then request permissions
* #return true if location permissions are granted
*/
private boolean isPermissionsGranted(boolean request) {
if (ActivityCompat.checkSelfPermission(mActivity,
Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(mActivity,
Manifest.permission.ACCESS_COARSE_LOCATION) !=
PackageManager.PERMISSION_GRANTED) {
if (request) {
ActivityCompat.requestPermissions(mActivity,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION},
PERMISSIONS_REQUEST);
}
return false;
}
return true;
}
private GoogleApiClient getGoogleApiClient(){
return new GoogleApiClient.Builder(mActivity)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
private void resolveProblems(int requestCode, int resultCode){
switch (requestCode){
case SETTINGS_CHECK:
switch (resultCode){
case Activity.RESULT_OK:
getLastKnownLocation();
break;
case Activity.RESULT_CANCELED:
mReceiver.userRefusedToSendLocation();
break;
}
break;
case GOOGLE_API_CLIENT_ERROR:
switch (resultCode) {
case Activity.RESULT_OK:
mGoogleApiClient.connect();
break;
case Activity.RESULT_CANCELED:
mReceiver.unableToObtainLocation();
break;
}
}
}
}
I use the code below in my project to retrieve the current location of the user. However, this seems to work on my test devices of API Level 23, but does not work on my test devices of API levels 19 to 22. The request for a location will return null and therefor place me at coordinates 0,0..
How can i get correct coordinates for API levels 19 to 22?
package be.enventorslab.pingvalue;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.location.Location;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import be.enventorslab.pingvalue.functions.Functions;
public class NearbyLocationActivity extends AppCompatActivity
implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
public static final String TAG = NearbyLocationActivity.class.getSimpleName();
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
private GoogleMap mMap;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
Bundle bundle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nearby_map);
setUpMapIfNeeded();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(10 * 1000)
.setFastestInterval(1 * 1000)
.setSmallestDisplacement(1);
}
#Override
protected void onStart() {
super.onStart();
setUpMapIfNeeded();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
}
private void setUpMapIfNeeded() {
if (mMap == null) {
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
}
}
#Override
public void onConnected(Bundle bundle) {
if (Functions.Permissions.getFineLocation(this)) {
Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (location == null) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
} else {
handleNewLocation(location);
}
} else {
this.bundle = bundle;
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} else {
Log.i(TAG, "Location services connection failed with code " + connectionResult.getErrorCode());
}
}
#Override
public void onLocationChanged(Location location) {
handleNewLocation(location);
}
private void handleNewLocation(Location location) {
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions options = new MarkerOptions().position(latLng).title("I am here!");
mMap.addMarker(options);
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
if (requestCode == Functions.Permissions.MY_PERMISSIONS_FINE_LOCATION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
onConnected(bundle);
}
}
}
}
For some reason it only updates the textviews when the app hits onPause, like when I hit the home button, or multitasking button. Can someone help me figure out why that is?
MainActivity.java:
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private String lat, lon;
private TextView longTextView, latTextView;
LocationService locationService = new LocationService(this);
private Intent intentService;
private PendingIntent pendingIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
latTextView = (TextView) findViewById(R.id.latitude_textview);
longTextView = (TextView) findViewById(R.id.longitude_textview);
}
#Override
protected void onStart() {
super.onStart();
locationService.buildGoogleApiClient();
locationService.apiConnect();
if (latTextView != null && longTextView != null) {
latTextView.setText( locationService.getLat());
longTextView.setText( locationService.getLon());
Toast.makeText(getApplicationContext(), " Actually got location", Toast.LENGTH_SHORT)
.show();
} else {
Toast.makeText(getApplicationContext(), "The shit was null fam", Toast.LENGTH_LONG)
.show();
}
}
#Override
protected void onStop() {
super.onStop();
locationService.apiDisconnect();
}
}
LocationService.java:
import android.Manifest;
import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.FusedLocationProviderApi;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import static com.google.android.gms.wearable.DataMap.TAG;
public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
// ============================================================= Variables
Context context;
Location mLastLocation;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private String lat, lon;
final static String[] LOCATION_PERMISSIONS = {Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION};
public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;
public static final long UPDATE_FASTEST_INTERVAL_IN_MILLISECONDS = UPDATE_INTERVAL_IN_MILLISECONDS / 2;
public static boolean isEnded = false;
public static Boolean requestingLocationUpdates;
protected String lastUpdateTime;
final int GOOGLEAPI_REQUEST_CODE = 24;
private FusedLocationProviderApi fusedLocationProviderApi = LocationServices.FusedLocationApi;
// ============================================================= Constructor
public LocationService(Context context) {
this.context = context;
}
// ============================================================= Getters / Setters
public String getLon() {
return lon;
}
public void setLon(String lon) {
this.lon = lon;
}
public String getLat() {
return lat;
}
public void setLat(String lat) {
this.lat = lat;
}
// ============================================================= Methods
synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
public void apiConnect() {
mGoogleApiClient.connect();
}
public void apiDisconnect() {
mGoogleApiClient.disconnect();
}
void updateUI() {
}
// ============================================================= Implemented Location Methods
#Override
public void onLocationChanged(Location location) {
setLat(String.valueOf(location.getLatitude()));
setLon(String.valueOf(location.getLongitude()));
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + connectionResult.getErrorCode());
}
#Override
public void onConnected(#Nullable Bundle bundle) {
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS); // Sets Location to update every second
mLocationRequest.setFastestInterval(UPDATE_FASTEST_INTERVAL_IN_MILLISECONDS); // The fastest location can update is every half-second
startLocationUpdates();
// TODO come back to this to see whats up
/* mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);*/
if (mLastLocation != null) {
setLat(String.valueOf(mLastLocation.getLatitude()));
setLon(String.valueOf(mLastLocation.getLongitude()));
}
}
#Override
public void onConnectionSuspended(int i) {
}
protected void startLocationUpdates() {
/*if (!requestingLocationUpdates) {
requestingLocationUpdates = true;*/
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions((Activity) context, LOCATION_PERMISSIONS, GOOGLEAPI_REQUEST_CODE);
} else {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
Log.i(TAG, " startLocationUpdates===");
isEnded = true;
//}
}
// ============================================================= Implemented Service Methods
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Within {#code onPause()}, we pause location updates, but leave the
// connection to GoogleApiClient intact. Here, we resume receiving
// location updates if the user has requested them.
Log.d("LOC", "Service init...");
isEnded = false;
requestingLocationUpdates = false;
lastUpdateTime = "";
buildGoogleApiClient();
if (mGoogleApiClient.isConnected() && requestingLocationUpdates) {
startLocationUpdates();
}
return Service.START_REDELIVER_INTENT;
}
}
The reason why you are not getting the location updated in textview is because your code doesn't have a way for the service to communicate back to the activity.
If you want to obtain location only when the activity is in foreground don't use Service and please look into this google's example for obtaining location and updating on a TextView using fused location provider.
I am not sure why you are using a Service.Use Service only when you want to continuously fetch the location even when the app is running background.
For this use any one of the method mentioned here to inform the activity that a new location has been obtained.LocalBroadcast would be your best bet. Anyway explore the best possible solution that suits your usecase in the previous link.