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;
}
}
}
}
Related
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.
I can't access my current location with this. I don't know what is the problem but. Every time I go to the map fragment on my navigation bar I can't see my current location.
Here is my code..
LanlordMapFragment.java
public class LanlordMapFragment extends Fragment implements OnMapReadyCallback {
private GoogleMap mMap;
public LanlordMapFragment() {
// Required empty public constructor
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_lanlord_map, container, false);
return v;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getActivity().setTitle("MAP");
SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map1);
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("My Location"));
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
mMap.setMyLocationEnabled(true);
return;
}
}
}
I've also experienced such type of problem:
Please, try to add the piece of code to your public View onCreateView(..){}
MapView m = (MapView) v.findViewById(R.id.source);
m.onCreate(savedInstanceState);
//try this code
mMap.setMyLocationEnabled(true);
mMap.getUiSettings().setMyLocationButtonEnabled(true);
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener()
{
#Override
public void onMapClick(LatLng latLng)
{
}
});
GetCurrentLocation location = new GetCurrentLocation(getActivity(), new GeocodingNotifier<Location>()
{
#Override
public void GeocodingDetails(Location geocodeLatLng) {
if (geocodeLatLng != null) {
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(geocodeLatLng.getLatitude(), geocodeLatLng.getLongitude()), 14f));
}
else {
// shaow erroe message
}
}
});
/// class to GetCurrentLocation
import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
public class GetCurrentLocation implements ConnectionCallbacks,
OnConnectionFailedListener, LocationListener {
private static final String TAG = GetCurrentLocation.class.getSimpleName();
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 1000;
public static Location mLastLocation=null;
public GoogleApiClient mGoogleApiClient;
private boolean mRequestingLocationUpdates = false;
private LocationRequest mLocationRequest;
private GeocodingNotifier mNotifier;
private static int UPDATE_INTERVAL = 10000; // 10 sec
private static int FATEST_INTERVAL = 5000; // 5 sec
private static int DISPLACEMENT = 10; // 10 meters
Activity mContext;
public GetCurrentLocation(Activity mContext, GeocodingNotifier mNotifier) {
this.mContext = mContext;
this.mNotifier = mNotifier;
if (checkPlayServices()) {
// Building the GoogleApi client
buildGoogleApiClient();
createLocationRequest();
}
}
public void setOnResultsListener(GeocodingNotifier mNotifier) {
this.mNotifier = mNotifier;
}
/**
* Method to display the location on UI
*/
private void displayLocation() {
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// 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;
}
mLastLocation = LocationServices.FusedLocationApi
.getLastLocation(mGoogleApiClient);
if (mLastLocation != null) {
double latitude = mLastLocation.getLatitude();
double longitude = mLastLocation.getLongitude();
}
}
/**
* Method to toggle periodic location updates
*/
private void togglePeriodicLocationUpdates() {
if (!mRequestingLocationUpdates) {
mRequestingLocationUpdates = true;
// Starting the location updates
startLocationUpdates();
Log.d(TAG, "Periodic location updates started!");
} else {
mRequestingLocationUpdates = false;
// Stopping the location updates
stopLocationUpdates();
Log.d(TAG, "Periodic location updates stopped!");
}
}
/**
* Creating google api client object
*/
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
}
/**
* Creating location request object
*/
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FATEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(DISPLACEMENT);
displayLocation();
}
/**
* Method to verify google play services on the device
*/
public boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil
.isGooglePlayServicesAvailable(mContext);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, mContext,
PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Toast.makeText(mContext,
"This device is not supported.", Toast.LENGTH_LONG)
.show();
}
return false;
}
return true;
}
/**
* Starting the location updates
*/
public void startLocationUpdates() {
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// 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);
}
/**
* Stopping location updates
*/
public void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
}
/**
* Google api callback methods
*/
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = "
+ result.getErrorCode());
}
#Override
public void onConnected(Bundle arg0) {
// Once connected with google api, get the location
displayLocation();
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int arg0) {
mGoogleApiClient.connect();
}
#Override
public void onLocationChanged(Location location) {
// Assign the new location
mLastLocation = location;
mNotifier.GeocodingDetails(mLastLocation);
displayLocation();
stopLocationUpdates();
mGoogleApiClient.disconnect();
}
}
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.
I am using the Google Play Services to find the current location.
But it is not going in any of the callback functions. Google API client cannot be connected.
Here is my code of the LocationUtil class:
package com.steporganization.util;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
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;
/**
* Created by Yogesh on 26-07-2015.
*/
public class LocationUtil implements GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener,LocationListener{
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 1000;
private final static String TAG="LocationUtil_Yogesh";
private GoogleApiClient client;
private Location location;
private boolean isClientConnected=false;
private Activity baseActivity;
private Context context;
private boolean isPlayServicesAvailable()
{
int resultCode= GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
if (resultCode!= ConnectionResult.SUCCESS)
{
if(GooglePlayServicesUtil.isUserRecoverableError(resultCode))
{
GooglePlayServicesUtil.getErrorDialog(resultCode,baseActivity,PLAY_SERVICES_RESOLUTION_REQUEST).show();
return false;
}
else
{
Toast.makeText(context,
"This device is not supported.", Toast.LENGTH_LONG)
.show();
return false;
}
}
return true;
}
private synchronized void buildGoogleAPiClient()
{
client=new GoogleApiClient.Builder(context).
addConnectionCallbacks(this).addOnConnectionFailedListener(this).
addApi(LocationServices.API).build();
}
private Location getLocation()
{
Location lastLocation;
lastLocation= LocationServices.FusedLocationApi.getLastLocation(client);
if(lastLocation==null)
{
//check for location
//requestlocation update until some location is acquired or timeout of 10 seconds
Long initialTime= System.currentTimeMillis();
Long finalTime=System.currentTimeMillis();
createLocationRequest();
while(this.location==null || finalTime-initialTime<20000)
{
finalTime=System.currentTimeMillis();
}
if(this.location==null)
{
Log.d(TAG,"Unable to fetch location");
LocationServices.FusedLocationApi.removeLocationUpdates(client,this);
return null;
}
else
LocationServices.FusedLocationApi.removeLocationUpdates(client,this);
return this.location;
}
else
return lastLocation;
}
#Override
public void onConnected(Bundle bundle) {
Log.d(TAG,"onConnected Called");
isClientConnected=true;
location=getLocation();
}
#Override
public void onConnectionSuspended(int i) {
Log.d(TAG,"onConnection suspended Called");
client.connect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.d(TAG,"onConnection Failed Called");
Log.d(TAG, "Error Code: " + connectionResult.getErrorCode());
}
protected void createLocationRequest()
{
LocationRequest locationRequest=new LocationRequest().
setInterval(1000).setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationServices.FusedLocationApi.requestLocationUpdates(client, locationRequest, this);
}
#Override
public void onLocationChanged(Location location) {
this.location=location;
}
public Location getUserCurrentLocation(Activity activity,Context context)
{
this.baseActivity=activity;
this.context=context;
if(isPlayServicesAvailable())
{
Log.d(TAG, "play services available");
buildGoogleAPiClient();
if(client!=null)
{
client.connect();
}
else
{
Log.d(TAG,"Cleint null");
}
while(isClientConnected!=true)
{
Log.d(TAG,"connecting API client");
}
return this.location;
}
else {
Log.d(TAG, "play service not available");
return null;
}
}
}
In another activity, I am creating an object of this class and calling getUserCurrentLocation(this,getApplicationContext()) function.
Can anybody suggest me what I am doing wrong here?
Also, it is not correct code, but my point is why it is not reaching inside any callback functions so that I can modify my logic as per my requirements.
Also, I found a similar question, but it has not been answered yet.