I have implemented a background service to receive location updates:
public class TestActivity extends Service implements LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private static String TAG = TestActivity_backup.class.getName();
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
private LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient=null;
#Override
public void onCreate() {
super.onCreate();
if (!isGooglePlayServicesAvailable()) {
stopSelf();
}
setContentView(R.layout.activity_test);
// Create the LocationRequest object
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(10000).setFastestInterval(5000).setSmallestDisplacement(20);
this.buildGoogleApiClient();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
this.destination = intent.getStringExtra("DESTINATION");
LatLng latLng = intent.getParcelableExtra("LOCATION");
this.location = new Location("");
this.location.setLatitude(latLng.latitude);
this.location.setLongitude(latLng.longitude);
return START_NOT_STICKY;
}
#Override
public void onLocationChanged(Location location){
Toast.makeText(TestActivity.this, "User location changed", Toast.LENGTH_SHORT).show();
}
#Override
public void onConnected(Bundle bundle) {
Toast.makeText(TestActivity.this, "Location service connected", Toast.LENGTH_SHORT).show();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Location services suspended. Please reconnect.");
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
//TODO
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
private boolean isGooglePlayServicesAvailable() {
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (ConnectionResult.SUCCESS == status) {
return true;
} else {
//GooglePlayServicesUtil.getErrorDialog(status, this, 0).show();
return false;
}
}
}
I have implemented all relevant methods.onCreate and onStartCommand are called but onConnec
ted and onLocationChanged are never ever called.If I implement an activity for location updates then its working fine.
What am I missing here?
Don't forget to add permission ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION depending upon Accuracy
And use this Code
public class LocationService extends Service {
private LocationListener locationListener;
#Override
public IBinder onBind(final Intent intent) {
return null;
}
#Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
super.onStartCommand(intent, flags, startId);
return Service.START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
final LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
this.locationListener = new MyLocationListener();
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 100, 0, this.locationListener);
}
private static class MyLocationListener implements LocationListener {
#Override
public void onLocationChanged(final Location location) {
}
#Override
public void onProviderDisabled(final String provider) {
}
#Override
public void onProviderEnabled(final String provider) {
}
#Override
public void onStatusChanged(final String provider, final int status, final Bundle extras) {
}
}
}
Here is my code that worked for me!
Don't forget to add mgoogleApiClient.connect() in onCreate()
and then take a look at the onConnected Method of googleapiClient - here I've created the the LocationRequest with
LocationServices.FusedLocationApi.requestLocationUpdates(
googleApiClient, mLocationRequest, this);
and then for testing I used
LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
for the initial Request.
If you are using emulator don't forget to telnet localhost 5543 (to your emulator) and then use the command geo fix to set the initial location.
You can test it with geofixing to another location then the onLocationChanged Methode should be called ...
package com.pekam.androidservice;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.pekam.myandroidtheme.*;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.location.*;
import com.google.android.gms.location.LocationListener;
public class MyService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,LocationListener {
private NotificationManager nm;
private Timer timer = new Timer();
private int counter = 0;
private int incrementby = 1;
private static boolean isRunning = false;
private GoogleApiClient googleApiClient;
private LocationRequest mLocationRequest = new LocationRequest();
private String strLOG="LOG";
ArrayList<Messenger> mClients = new ArrayList<Messenger>(); // Keeps track of all current registered clients.
int mValue = 0; // Holds last value set by a client.
static final int MSG_REGISTER_CLIENT = 1;
static final int MSG_UNREGISTER_CLIENT = 2;
static final int MSG_SET_INT_VALUE = 3;
static final int MSG_SET_STRING_VALUE = 4;
static final int MSG_SET_STRING_LOG =5;
final Messenger mMessenger = new Messenger(new IncomingHandler()); // Target we publish for clients to send messages to IncomingHandler.
// LocationRequest
#Override
public void onLocationChanged(Location location) {
Location mCurrentLocation = location;
sendLogMessageToUI("Last Known Loc" + mCurrentLocation.getLongitude() + mCurrentLocation.getLatitude());
}
//GoogleApiClient
#Override
public void onConnectionFailed(ConnectionResult bundle) {
}
#Override
public void onConnected(Bundle bundle) {
Log.i("onConnected", "GoogleApiClient" );
try {
Toast.makeText(this, "Location service connected", Toast.LENGTH_SHORT).show();
createLocationRequest();
LocationServices.FusedLocationApi.requestLocationUpdates(
googleApiClient, mLocationRequest, this);
LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
} catch (Throwable t) { //you should always ultimately catch all exceptions in timer tasks.
Log.e("Google APi Connected", "Google APi Connected Failed.", t);
}
}
#Override
public void onConnectionSuspended(int i) {
}
//Service
#Override
public void onCreate() {
super.onCreate();
Log.i("MyService", "Service Started.");
showNotification();
timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 0, 1900L);
isRunning = true;
try {
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
googleApiClient.connect();
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("MyService", "Received start id " + startId + ": " + intent);
return START_STICKY; // run until explicitly stopped.
}
#Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
public static boolean isRunning()
{
return isRunning;
}
private void onTimerTick() {
Log.i("TimerTick", "Timer doing work." + counter);
try {
counter += incrementby;
sendMessageToUI(counter);
// LocationServices.FusedLocationApi.setMockMode(googleApiClient, true);
// double latitude = LocationServices.FusedLocationApi.getLastLocation(googleApiClient).getLatitude();
} catch (Throwable t) { //you should always ultimately catch all exceptions in timer tasks.
Log.e("TimerTick", "Timer Tick Failed.", t);
}
}
private boolean isGooglePlayServicesAvailable() {
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (ConnectionResult.SUCCESS == status) {
return true;
} else {
//GooglePlayServicesUtil.getErrorDialog(status, this, 0).show();
return false;
}
}
private void showNotification() {
nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.service_started);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.ic_launcher, text, System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, TabBarActivity.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, getText(R.string.service_label), text, contentIntent);
// Send the notification.
// We use a layout id because it is a unique number. We use it later to cancel.
nm.notify(R.string.service_started, notification);
}
protected void createLocationRequest() {
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
private void sendMessageToUI(int intvaluetosend) {
for (int i=mClients.size()-1; i>=0; i--) {
try {
// Send data as an Integer
mClients.get(i).send(Message.obtain(null, MSG_SET_INT_VALUE, intvaluetosend, 0));
//Send data as a String
Bundle b = new Bundle();
b.putString("str1", "ab" + intvaluetosend + "cd");
Message msg = Message.obtain(null, MSG_SET_STRING_VALUE);
msg.setData(b);
mClients.get(i).send(msg);
} catch (RemoteException e) {
// The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop.
mClients.remove(i);
}
}
}
private void sendLogMessageToUI(String strLOG) {
for (int i=mClients.size()-1; i>=0; i--) {
try {
// Send data as an Integer
mClients.get(i).send(Message.obtain());
//Send data as a String
Bundle b = new Bundle();
b.putString("strLOG", strLOG);
Message msg = Message.obtain(null, MSG_SET_STRING_LOG);
msg.setData(b);
mClients.get(i).send(msg);
} catch (RemoteException e) {
// The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop.
mClients.remove(i);
}
}
}
class IncomingHandler extends Handler { // Handler of incoming messages from clients.
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_CLIENT:
mClients.add(msg.replyTo);
break;
case MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
break;
case MSG_SET_INT_VALUE:
incrementby = msg.arg1;
break;
default:
super.handleMessage(msg);
}
}
}
}
Related
In my app, I have a speedometer class and I want to be able to say in my Broadcast Receiver class that when the speed goes over 25, do some action.
How would I go about doing that?
I have searched various questions but all lead me to a dead end.
Heres the Speedometer Code
package com.rrithvik.idrive;
import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.Nullable;
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 java.text.DecimalFormat;
import java.util.concurrent.TimeUnit;
/**
* Created by vipul on 12/13/2015.
*/
public class LocationService extends Service implements
LocationListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private static final long INTERVAL = 1000 * 2;
private static final long FASTEST_INTERVAL = 1000 * 1;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mCurrentLocation, lStart, lEnd;
static double distance = 0;
double speed;
private final IBinder mBinder = new LocalBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
createLocationRequest();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
return mBinder;
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onConnected(Bundle bundle) {
try {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
} catch (SecurityException e) {
}
}
protected void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
distance = 0;
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onLocationChanged(Location location) {
MainActivity.locate.dismiss();
mCurrentLocation = location;
if (lStart == null) {
lStart = mCurrentLocation;
lEnd = mCurrentLocation;
} else
lEnd = mCurrentLocation;
//Calling the method below updates the live values of distance and speed to the TextViews.
updateUI();
//calculating the speed with getSpeed method it returns speed in m/s so we are converting it into kmph
speed = location.getSpeed() * 2.24;
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
public class LocalBinder extends Binder {
public LocationService getService() {
return LocationService.this;
}
}
//The live feed of Distance and Speed are being set in the method below .
private void updateUI() {
if (MainActivity.p == 0) {
distance = distance + (lStart.distanceTo(lEnd) * 0.00062);
MainActivity.endTime = System.currentTimeMillis();
long diff = MainActivity.endTime - MainActivity.startTime;
diff = TimeUnit.MILLISECONDS.toMinutes(diff);
MainActivity.time.setText("Total Time: " + diff + " minutes");
if (speed > 0.0) {
MainActivity.speed.setText("Current speed: " + new DecimalFormat("#.##").format(speed) + " mph");
}
else {
MainActivity.speed.setText(".......");
}
MainActivity.dist.setText("Total Distance " + new DecimalFormat("#.###").format(distance) + " miles.");
lStart = lEnd;
}
}
#Override
public boolean onUnbind(Intent intent) {
stopLocationUpdates();
if (mGoogleApiClient.isConnected())
mGoogleApiClient.disconnect();
lStart = null;
lEnd = null;
distance = 0;
return super.onUnbind(intent);
}
}
So once again, this action has to be done in the Broadcast Receiver Class
Maybe this is what you are searching
double speedNum = Double.parseDouble(speed)
and then do the checking whether the speedNum is larger than 25 or not.
If you convert your String to a Double value, you will can verify this number.
double speedDouble = Double.parseDouble(speedText);
if(speedDouble > 25) {
// Do something
}
I want to run location update as a service. Now I can able to run the service correctly but the location updation is happening twice, Here is the code,
AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<service
android:name=".services.LocationService"
android:icon="#drawable/ic_location"
android:label="Location Service">
<intent-filter>
<action android:name="android.service.notification.service" />
</intent-filter>
</service>
In the Activity Class we are using startLocationService() to start the service and stopLocationService() to stop the service, Also created a Broadcast Receiver to get the location updation on the Activity Calss.
private BroadcastReceiver broadcastReceiver;
private Intent mLocationServiceIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_navigtaion_drawer);
AppController.getInstance().activityResumed();
broadcastReceiver = createBroadcastReceiver();
registerReceiver(broadcastReceiver, new IntentFilter(getPackageName()));
if (!Permissions.hasLocationPermission(this)) {
Permissions.requestLocationPermission(this, PermissionKeys.LOCATION_REQUEST_HOME_ON_RESUME);
} else
startLocationService();
}
private BroadcastReceiver createBroadcastReceiver() {
return new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra(LocationService.LOCATION_UPDATED)) {
Bundle b = intent.getExtras();
if (b != null) {
Location mCurrentLocation = (Location) b.get(LocationService.LOCATION_UPDATED);
}
}
}
};
}
//Function To Start the Service
public void startLocationService() {
if (mLocationServiceIntent == null)
mLocationServiceIntent = new Intent(this, LocationService.class);
startService(mLocationServiceIntent);
}
//Function To Stop the Service
public void stopLocationService() {
if (mLocationServiceIntent != null)
stopService(mLocationServiceIntent);
}
LocationService.java
public class LocationService extends Service implements LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
public static final String LOCATION_UPDATED = "LocationUpdated";
public static final String LATITUDE = "Latitude";
public static final String LONGITUDE = "Longitude";
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
private static final String TAG = "###LocationService:: ";
private static final int LOCATION_INTERVAL = 15000;
private static final int FASTEST_INTERVAL = 10000;
private static final float LOCATION_DISTANCE = 7f;
#Override
public void onCreate() {
if (isGooglePlayServicesAvailable()) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(LOCATION_INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
//mLocationRequest.setSmallestDisplacement(10.0f); /* min dist for location change, here it is 10 meter */
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
}
}
//Check Google play is available or not
private boolean isGooglePlayServicesAvailable() {
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
return ConnectionResult.SUCCESS == status;
}
#Override
public void onConnected(Bundle bundle) {
Log.e(TAG, "Connected");
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
Log.e(TAG, "Connection suspended");
}
protected void startLocationUpdates() {
Log.e(TAG, "Start Location Updates");
try {
int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
PendingResult<Status> pendingResult = LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
} catch (IllegalStateException e) {
}
}
#Override
public void onLocationChanged(Location location) {
if (location != null) {
Log.e(TAG, "Location Changed : " + location.getLatitude() + "," + location.getLongitude());
Intent intent = new Intent(getPackageName());
intent.putExtra(LOCATION_UPDATED, location);
sendBroadcast(intent);
}
}
/* LocationListener[] mLocationListeners = new LocationListener[]{
new LocationListener(LocationManager.GPS_PROVIDER),
new LocationListener(LocationManager.NETWORK_PROVIDER)
};*/
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.e(TAG, "onConnectionFailed:: "+connectionResult.getErrorMessage());
}
}
I have fixed this issue by adding a condition checking before start the service,
My updated startLocationService() function is like,
//Function To Start the Service
public void startLocationService() {
if (mLocationServiceIntent == null)
mLocationServiceIntent = new Intent(this, LocationService.class);
if(!isServiceRunning(HomeScreenActivity.this, LocationService.class)) {
startService(mLocationServiceIntent);
}
}
Here is the function to check if the service is already running or not.
//This function is to check the service is already running or not
public boolean isServiceRunning(Context context, Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
Log.e("ServiceRunning", serviceClass.getSimpleName() + " is alredy running");
return true;
}
}
return false;
}
I want to get location updates on a "background service" using latest fused location provider client.I don't want to use the location listeners and Google API Client that all are using.
I also need to use location settings Api provided by google play services to check whether location setting are disable or enable on that "background service".Please help.
if we need to use fusion location api then we need to use Google API client, For the background service it is not an issue to use it, Following is the example which I used for getting location update in background, But one more thing as Google introduces 'DOZE' mode from 6.0 so I can not give surety give update when your device in 'DOZE' mode,
import android.Manifest;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
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.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;
/**
* Created By Dhaval Solanki
*/
public class ConnectionService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
String TAG = "ConnectionService";
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private Location previousLocation;
public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 30000;
public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
UPDATE_INTERVAL_IN_MILLISECONDS / 2;
private Location mLastLocation;
private Context context;
#Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind");
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
context = getApplicationContext();
Log.i(TAG, "onStartCommand");
if (checkPermsion(context)) {
setupLocationService(context);
}
return Service.START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
ApplicationCLass.isServiceRunning = true;
}
#Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind");
ApplicationCLass.isServiceRunning = false;
return super.onUnbind(intent);
}
#Override
public void onDestroy() {
ApplicationCLass.isServiceRunning = false;
super.onDestroy();
}
private void setupLocationService(Context context) {
if (checkPlayServices()) {
mGoogleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
createLocationRequest();
}
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest().create();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
mGoogleApiClient.connect();
}
public boolean checkPermsion(Context context) {
int MyVersion = Build.VERSION.SDK_INT;
if (MyVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return false;
} else if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return false;
} else {
return true;
}
} else {
return true;
}
}
private boolean checkPlayServices() {
GoogleApiAvailability googleAPI = GoogleApiAvailability.getInstance();
int result = googleAPI.isGooglePlayServicesAvailable(this);
if (result != ConnectionResult.SUCCESS) {
return false;
}
return true;
}
private void startLocationUpdates() {
if (mGoogleApiClient.isConnected()) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
if (Prefs.getUserLat(context).trim().length() > 0 && Prefs.getUserLong(context).trim().length() > 0) {
} else {
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
if (mLastLocation != null) {
Prefs.setUserLat(context, String.valueOf(mLastLocation.getLatitude()));
Prefs.setUserLong(context, String.valueOf(mLastLocation.getLongitude()));
}
}
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.i(TAG, "Connected to onConnected");
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "Connected to onConnectionSuspended");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.i(TAG, "Connected to onConnectionFailed");
}
#Override
public void onLocationChanged(Location location) {
try {
Logger.print("onLocationChanged", "latitued :" + location.getLatitude() + " ,, Longitude " + location.getLongitude());
} catch (Exception e) {
e.printStackTrace();
}
}
}
One another alaram service continues runnning or not
import android.app.ActivityManager;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class AlarmService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
boolean isServiceRunning = false;
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (ConnectionService.class.getName().equals(service.service.getClassName())) {
isServiceRunning = true;
break;
}
}
Log.i("AlarmService", "Service is running " + isServiceRunning);
if(!isServiceRunning) {
startService(new Intent(getApplicationContext(),ConnectionService.class));
} else {
ConnectionService.checkConnectionAndConnect(getApplicationContext());
}
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*/
public AlarmService() {
super("AlaramService");
}
}
And Finaly start service
private void checkAndStartService() {
final ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
new AsyncTask<Void, Void, Boolean>() {
boolean isServiceRunning = false;
#Override
protected Boolean doInBackground(Void... params) {
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (ConnectionService.class.getName().equals(service.service.getClassName())) {
isServiceRunning = true;
break;
}
}
return isServiceRunning;
}
#Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
Log.i("onPostExecute", "Service running = " + aBoolean);
if (!aBoolean) {
startService(new Intent(ActivitySplash.this, ConnectionService.class));
Intent i = new Intent(ActivitySplash.this, AlarmService.class);
PendingIntent pi = PendingIntent.getService(ActivitySplash.this, 0, i, 0);
AlarmManager am = (AlarmManager) ActivitySplash.this.getSystemService(Context.ALARM_SERVICE);
am.cancel(pi); // cancel any existing alarms
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 60000, pi);
}
}
}.execute();
}
You can write the code for the intentService as given below. It has been considered that since it is running in the background, we would not show the permission dialogs.
public class GetLocationService extends IntentService
implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
public static String TAG = GetLocationService.class.getSimpleName();
private GoogleApiClient mGoogleApiClient;
public GetLocationService() {
super(TAG);
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* #param name Used to name the worker thread, important only for debugging.
*/
public GetLocationService(String name) {
super(name);
}
#Override
protected void onHandleIntent(Intent intent) {
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
Log.d(TAG, "disconnecting");
mGoogleApiClient.disconnect();
}
Log.d(TAG, "onHandleIntent");
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationRequest locationRequestLow = LocationRequest.create();
locationRequestLow.setPriority(LocationRequest.PRIORITY_LOW_POWER);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_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.
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, locationRequest, this);
} else {
Log.d(TAG, "permission denied");
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, location.toString());
}
}
You can extend the service class like
public class BackgroundLocationService extends Service implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener,
LocationListener
You can check the full source code here BackgroundLocationService.java
For enable location settings
private void displayLocationSettingsRequest() {
GoogleApiClient googleApiClient = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API).build();
googleApiClient.connect();
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(10000);
locationRequest.setFastestInterval(10000 / 2);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(locationRequest);
builder.setAlwaysShow(true);
PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(#NonNull LocationSettingsResult result) {
final Status status = result.getStatus();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
// Show the dialog by calling startResolutionForResult(), and check the result
// in onActivityResult().
status.startResolutionForResult(context, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException ignored) {
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
break;
}
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
// Check for the integer request code originally supplied to
startResolutionForResult().
case REQUEST_CHECK_SETTINGS:
switch (resultCode) {
case Activity.RESULT_OK:
//startLocationUpdates();
break;
case Activity.RESULT_CANCELED:
displayLocationSettingsRequest();//keep asking
showToast("Location permission needed");
break;
}
break;
}
}
You can check location settings from Service and if location is off ,
LocationManager lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
boolean gps_enabled = false;
boolean network_enabled = false;
try {
gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
} catch(Exception ex) {}
try {
network_enabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch(Exception ex) {}
if(!gps_enabled && !network_enabled) {
// notify user
// Either you can display a Notification(Recommended way) or you can show dialog with
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
//It needs SYSTEM_ALERT_WINDOW permission. Add this permission in Manifest.
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
}
Hi I have good understanding about location services and how we can use in it perfect way. See i'll give you idea about fused apis.
Just make sure follow the below steps. It is pretty nice and simple.
Step 1. Make this class
GoogleLocationService.java
public class GoogleLocationService {
private GoogleServicesCallbacks callbacks = new GoogleServicesCallbacks();
LocationUpdateListener locationUpdateListener;
Context activity;
protected GoogleApiClient mGoogleApiClient;
protected LocationRequest mLocationRequest;
public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 30000;
public GoogleLocationService(Context activity, LocationUpdateListener locationUpdateListener) {
this.locationUpdateListener = locationUpdateListener;
this.activity = activity;
buildGoogleApiClient();
}
protected synchronized void buildGoogleApiClient() {
//Log.i(TAG, "Building GoogleApiClient");
mGoogleApiClient = new GoogleApiClient.Builder(activity)
.addConnectionCallbacks(callbacks)
.addOnConnectionFailedListener(callbacks)
.addApi(LocationServices.API)
.build();
createLocationRequest();
mGoogleApiClient.connect();
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
private class GoogleServicesCallbacks implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
#Override
public void onConnected(Bundle bundle) {
startLocationUpdates();
}
#Override
public void onConnectionSuspended(int i) {
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
if (connectionResult.getErrorCode() == ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED) {
Toast.makeText(activity, "Google play service not updated", Toast.LENGTH_LONG).show();
}
locationUpdateListener.cannotReceiveLocationUpdates();
}
#Override
public void onLocationChanged(Location location) {
if (location.hasAccuracy()) {
if (location.getAccuracy() < 30) {
locationUpdateListener.updateLocation(location);
}
}
}
}
private static boolean locationEnabled(Context context) {
boolean gps_enabled = false;
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
try {
gps_enabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
} catch (Exception ex) {
ex.printStackTrace();
}
return gps_enabled;
}
private boolean servicesConnected(Context context) {
return isPackageInstalled(GooglePlayServicesUtil.GOOGLE_PLAY_STORE_PACKAGE, context);
}
private boolean isPackageInstalled(String packagename, Context context) {
PackageManager pm = context.getPackageManager();
try {
pm.getPackageInfo(packagename, PackageManager.GET_ACTIVITIES);
return true;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return false;
}
}
public void startUpdates() {
/*
* Connect the client. Don't re-start any requests here; instead, wait
* for onResume()
*/
if (servicesConnected(activity)) {
if (locationEnabled(activity)) {
locationUpdateListener.canReceiveLocationUpdates();
startLocationUpdates();
} else {
locationUpdateListener.cannotReceiveLocationUpdates();
Toast.makeText(activity, "Unable to get your location.Please turn on your device Gps", Toast.LENGTH_LONG).show();
}
} else {
locationUpdateListener.cannotReceiveLocationUpdates();
Toast.makeText(activity, "Google play service not available", Toast.LENGTH_LONG).show();
}
}
//stop location updates
public void stopUpdates() {
stopLocationUpdates();
}
//start location updates
private void startLocationUpdates() {
if (checkSelfPermission(activity, ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && checkSelfPermission(activity, ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, callbacks);
}
}
public void stopLocationUpdates() {
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, callbacks);
}
}
public void startGoogleApi() {
mGoogleApiClient.connect();
}
public void closeGoogleApi() {
mGoogleApiClient.disconnect();
}
}
Step2. Make this interface
LocationUpdateListener.java
public interface LocationUpdateListener {
/**
* Called immediately the service starts if the service can obtain location
*/
void canReceiveLocationUpdates();
/**
* Called immediately the service tries to start if it cannot obtain location - eg the user has disabled wireless and
*/
void cannotReceiveLocationUpdates();
/**
* Called whenever the location has changed (at least non-trivially)
* #param location
*/
void updateLocation(Location location);
/**
* Called when GoogleLocationServices detects that the device has moved to a new location.
* #param localityName The name of the locality (somewhere below street but above area).
*/
void updateLocationName(String localityName, Location location);
}
Step 3. Make this Location service class
LocationService.java
public class LocationService extends Service {
private GoogleLocationService googleLocationService;
#Override
public void onCreate() {
super.onCreate();
//start the handler for getting locations
//create component
updateLocation(getApplicationContext());
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
//get current location os user
private void updateLocation(Context context) {
googleLocationService = new GoogleLocationService(context, new LocationUpdateListener() {
#Override
public void canReceiveLocationUpdates() {
}
#Override
public void cannotReceiveLocationUpdates() {
}
//update location to our servers for tracking purpose
#Override
public void updateLocation(Location location) {
if (location != null ) {
Timber.e("updated location %1$s %2$s", location.getLatitude(), location.getLongitude());
}
}
#Override
public void updateLocationName(String localityName, Location location) {
googleLocationService.stopLocationUpdates();
}
});
googleLocationService.startUpdates();
}
IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
public LocationService getServerInstance() {
return LocationService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
//stop location updates on stopping the service
#Override
public void onDestroy() {
super.onDestroy();
if (googleLocationService != null) {
googleLocationService.stopLocationUpdates();
}
}
}
Edited Answer:
How to use service,
Start service in your main activity,like this
startService(new Intent(context, LocationService.class));
for stop,
stopService(new Intent(context, LocationService.class));
and declare in manifest like this,
<service
android:name=".service.location.LocationService"
android:enabled="true"></service>
Note: I have done this because i need location after killed the app.If you dont want service.Then,you can call directly below code in class where location need to be update and remove locationservice.
private GoogleLocationService googleLocationService;
googleLocationService = new GoogleLocationService(context, new LocationUpdateListener() {
#Override
public void canReceiveLocationUpdates() {
}
#Override
public void cannotReceiveLocationUpdates() {
}
//update location to our servers for tracking purpose
#Override
public void updateLocation(Location location) {
if (location != null ) {
Timber.e("updated location %1$s %2$s", location.getLatitude(), location.getLongitude());
}
}
#Override
public void updateLocationName(String localityName, Location location) {
googleLocationService.stopLocationUpdates();
}
});
googleLocationService.startUpdates();
and call this onDestroy
if (googleLocationService != null) {
googleLocationService.stopLocationUpdates();
}
Remember Locationservice should be declare in manifest as well.
According to me this is the best solution.
Thanks hope this will help you
The question does not appear to be very specific. It seems like you're having trouble starting up with using location services.
The best idea would probably be checking out the Google samples (https://github.com/googlesamples/android-play-location) to better understand the mechanics.
I would probably start by implementing the simplest example (LocationUpdates). It uses the FusedLocationProvider and also checks if the settings are enabled, so it should fit your needs, or at least get you started.
If you really need to use a service you can check out LocationUpdatesForegroundService or LocationUpdatesPendingIntent. But I would strongly recommend to read and understand the first example before you do this.
I've searched for days and days and somehow the answer to why onLocationChanged isn't being called has eluded me. I've read the documentation extensively and I MUST be missing something crucial. I simply want a service that runs in the background, when location has changed, I want to log the location.
Here's my service...
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
import android.support.annotation.Nullable;
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;
public class BackgroundLocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private final String TAG = ((Object) this).getClass().getSimpleName();
IBinder mBinder = new LocalBinder();
GoogleApiAvailability googleAPI;
PowerManager.WakeLock mWakeLock;
private boolean mInProgress;
private Boolean servicesAvailable = false;
protected GoogleApiClient mGoogleApiClient;
protected LocationRequest mLocationRequest;
private Intent mIntentService;
private PendingIntent mPendingIntent;
public class LocalBinder extends Binder {
public BackgroundLocationService getServerInstance() {
return BackgroundLocationService.this;
}
}
#Override
public void onCreate() {
super.onCreate();
googleAPI = GoogleApiAvailability.getInstance();
mInProgress = false;
mIntentService = new Intent(this,BackgroundLocationService.class);
mPendingIntent = PendingIntent.getService(this, 1, mIntentService, PendingIntent.FLAG_UPDATE_CURRENT);
servicesAvailable = servicesConnected();
/*
* Create a new google api client, using the enclosing class to handle callbacks.
*/
buildGoogleApiClient();
}
private boolean servicesConnected() {
// Check that Google Play services is available
int resultCode = googleAPI.isGooglePlayServicesAvailable(this);
// If Google Play services is available
if (ConnectionResult.SUCCESS == resultCode) {
return true;
} else {
return false;
}
}
protected void startLocationUpdates() {
Log.i(TAG, "Started Location Updates");
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, mPendingIntent);
}
protected void stopLocationUpdates() {
Log.i(TAG,"Stopped Location Updates");
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, mPendingIntent);
}
protected void createLocationRequest() {
Log.i(TAG, "createLocationRequest()");
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(5000);
mLocationRequest.setFastestInterval(1000);
//mLocationRequest.setMaxWaitTime(10000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
PowerManager mgr = (PowerManager) getSystemService(Context.POWER_SERVICE); //*** added this
if (this.mWakeLock == null) {
mWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "aWakeLock"); //*** added this
}
if (!this.mWakeLock.isHeld()) {
mWakeLock.acquire(); //*** added this
}
if (!servicesAvailable || mGoogleApiClient.isConnected() || mInProgress)
return START_STICKY;
if (!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress) {
Log.e(TAG, "Location Client not connected, connecting...");
mInProgress = true;
mGoogleApiClient.connect();
}
Log.e(TAG, "Location Client: onStartCommand");
return START_STICKY;
}
protected synchronized void buildGoogleApiClient() {
Log.i(TAG, "Building GoogleApiClient");
if (mGoogleApiClient == null) {
this.mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
createLocationRequest();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onDestroy() {
// Turn off the request flag
this.mInProgress = false;
if (this.mWakeLock != null) {
this.mWakeLock.release();
this.mWakeLock = null;
}
Log.e(TAG, "Location Client: ON DESTROY");
super.onDestroy();
stopLocationUpdates();
}
#Override
public void onConnected(Bundle bundle) {
startLocationUpdates();
}
#Override
public void onLocationChanged(Location location) {
Log.e(TAG, "Location Receiver [Location Changed]: " + location.getLatitude() + ", " + location.getLongitude());
}
#Override
public void onConnectionSuspended(int i) {
Log.e(TAG, "Location Client: ON CONNECTED");
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
mInProgress = false;
Log.e(TAG, "Location Client: ON CONNECTION FAILED");
if (connectionResult.hasResolution()) {
// If no resolution is available, display an error dialog
} else {
}
}
}
I'm starting the service like this...
Intent BackgroundLocationService = new Intent(this, BackgroundLocationService.class);
startService(BackgroundLocationService);
I have the following permission in the manifest as well...
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
The requestLocationUpdates uses a pendingintent currently which is fired to start the service again. This is not calling the OnLocationchanged callback. Try using the requestLocationUpdates with location listener (3rd parameter). It should call OnLocationchanged.
I have location tracker app and there is a class, handling the location changing. On 4.2.2 device is works normally - onLocationChanged() callback react. But on other device - lollypop - same code never calls onLocationChanged(). 've tried with GPS enabled/disabled and internet enabled/disabled in all combination. Turning on/off GPS module during app runtime change nothing. I have no clue, where can i find a solution to this problem. Help please.
package kgk.tracker;
import android.content.Context;
import android.location.GpsSatellite;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
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;
import de.greenrobot.event.EventBus;
import kgk.tracker.messages.GPS;
public class LocationProvider implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener,
GpsStatus.Listener {
public static final String TAG = LocationProvider.class.getSimpleName();
public final static int PLAY_SERVICES_RESOLUTION_REQUEST = 1000;
private static LocationProvider locationProvider;
// Объект - клиент сервиса Google Play
private GoogleApiClient googleApiClient;
// Параметры запроса на предоставление координат для Google Play
private LocationRequest locationRequest;
// Объект LocationManager для определения количества используемых спутников
private LocationManager locationManager;
private static int satellitesCount = 0;
// Конструкторы
private LocationProvider() {
locationManager = (LocationManager) KGKTracker.getAppContext().getSystemService(Context.LOCATION_SERVICE);
locationManager.addGpsStatusListener(this);
createLocationRequest();
buildGoogleApiClient();
EventBus.getDefault().register(this);
android.location.LocationListener locationListener = new android.location.LocationListener() {
#Override
public void onLocationChanged(Location location) {
// Используется другая реалзиация данного метода в библиотеке FusedLocationApi
}
#Override
public void onProviderDisabled(String arg0) {
Log.d("GPS", "Provider disabled");
kgk.tracker.LocationProvider.setSatellitesCount(0);
CommunicationService.setGps_enabled(false);
CommunicationService.getCommunicationService().generateEmptyPacket();
CommunicationService.getCommunicationService().gpsLost();
}
#Override
public void onProviderEnabled(String arg0) {
Log.d("GPS", "Provider enabled");
CommunicationService.setGps_enabled(true);
CommunicationService.getCommunicationService().generateEmptyPacket();
}
#Override
public void onStatusChanged(String provider, int status, Bundle arg2) {
Log.d("GPS STATUS", "STATUS CHANGED");
switch (status) {
case android.location.LocationProvider.AVAILABLE:
Log.d("GPS STATUS", "AVAILABLE");
//gpsFound();
break;
default:
Log.d("GPS STATUS", "LOST");
//gpsLost();
break;
}
}
};
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 0, locationListener);
}
public static LocationProvider getInstance() {
if (locationProvider == null) {
return new LocationProvider();
} else {
return locationProvider;
}
}
// Аксессоры
public static int getSatellitesCount() {
return satellitesCount;
}
public static void setSatellitesCount(int satellitesCount) {
LocationProvider.satellitesCount = satellitesCount;
}
public GoogleApiClient getGoogleApiClient() {
return googleApiClient;
}
// Открытые методы
/**
* Обработка ивента с помощью библиотеки EventBus
*/
public void onEvent(LocationEvent locationEvent) {
if (locationEvent.getDoConnect()) {
if (!googleApiClient.isConnected()) {
googleApiClient.connect();
}
} else {
googleApiClient.disconnect();
}
}
// Внутренние методы
/**
* Создание объекта GoogleApiClient
*/
private synchronized void buildGoogleApiClient() {
googleApiClient = new GoogleApiClient.Builder(KGKTracker.getAppContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
}
/**
* Создание LocationRequest
*/
private void createLocationRequest() {
locationRequest = LocationRequest.create()
.setInterval(5000)
.setFastestInterval(5000)
.setSmallestDisplacement(0.0f)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
/**
* Возвращает количество используемых спутников
*/
private int checkSatellitesCount() {
int satellitesInUse = 0;
for (GpsSatellite satellite : locationManager.getGpsStatus(null).getSatellites()) {
if (satellite.usedInFix()) {
satellitesInUse++;
}
}
return satellitesInUse;
}
// Реализация интерфейсов
#Override
public void onConnected(Bundle bundle) {
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
#Override
public void onConnectionSuspended(int i) {
switch (i) {
case CAUSE_SERVICE_DISCONNECTED:
Log.d(TAG, "CAUSE_SERVICE_DISCONNECTED");
break;
case CAUSE_NETWORK_LOST:
Log.d(TAG, "CAUSE_SERVICE_DISCONNECTED");
break;
default:
Log.d(TAG, "Unknown reason");
break;
}
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.d(TAG, "onConnectionFailed " + connectionResult);
if (connectionResult.getErrorCode() == ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED) {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(MainActivity.getMainActivity());
GooglePlayServicesUtil.getErrorDialog(resultCode, MainActivity.getMainActivity(), PLAY_SERVICES_RESOLUTION_REQUEST).show();
}
}
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, "Current location at: " + location.getLatitude() + " " + location.getLongitude() + " " + satellitesCount);
CommunicationService service = CommunicationService.getCommunicationService();
if (service != null) {
service.setLastPacket(new Packet(location));
long last_packet_id = DB.getInstance(KGKTracker.getAppContext()).write_packet(service.getLastPacket());
service.getLastPacket().setId(last_packet_id);
service.gpsFound();
try {
service.getMessageQueue().put(new GPS(service.getLastPacket()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void onGpsStatusChanged(int event) {
switch (event) {
case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
satellitesCount = checkSatellitesCount();
break;
default:
Log.d(TAG, "Unexpected behavior in onGpsStatusChanged callback");
break;
}
}
}