I used Location Service in my android application, which extends Service and implements the GoogleApiClient, LocationListener. I am updating location onLocationChanged() method and my loaction update interval is 20 second. Sometimes Location Service is not working even though the app is in the background. I want to run my location service always anyhow. Each and every version of Android & every mobile, even though the app is killing from background also.
I call location service using AlarmManager also.
I gave call for location update in onStartCommand() method .
If location service is stopped then it will go to the onDestroy() method or onTaskRemoved() method in that method again I am calling startLocation method like,
startService(new Intent(this, LocationService.class));
My manifest code for service:
<service
android:name=".LocationService"
android:enabled="true"
android:stopWithTask="false"
/>
you can create location service like below.which run on background and foreground mode
public class ServiceLocation extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private static final String NOTIFICATION_CHANNEL_ID = "my_notification_location";
private static final long TIME_INTERVAL_GET_LOCATION = 1000 * 5; // 1 Minute
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 7; // meters
private Handler handlerSendLocation;
private Context mContext;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 5000;
Location locationData;
#Override
public void onCreate() {
super.onCreate();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
// Create the LocationRequest object
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(TIME_INTERVAL_GET_LOCATION) // 3 seconds, in milliseconds
.setFastestInterval(TIME_INTERVAL_GET_LOCATION); // 1 second, in milliseconds
mContext = this;
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setOngoing(false)
.setSmallIcon(R.drawable.ic_notification)
.setColor(getResources().getColor(R.color.fontColorDarkGray))
.setPriority(Notification.PRIORITY_MIN);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_ID, NotificationManager.IMPORTANCE_LOW);
notificationChannel.setDescription(NOTIFICATION_CHANNEL_ID);
notificationChannel.setSound(null, null);
notificationManager.createNotificationChannel(notificationChannel);
startForeground(1, builder.build());
}
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.w("Service Update Location", "BGS > Started");
if (handlerSendLocation == null) {
handlerSendLocation = new Handler();
handlerSendLocation.post(runnableSendLocation);
Log.w("Service Send Location", "BGS > handlerSendLocation Initialized");
} else {
Log.w("Service Send Location", "BGS > handlerSendLocation Already Initialized");
}
return START_STICKY;
}
private Runnable runnableSendLocation = new Runnable() {
#Override
public void run() {
// You can get Location
//locationData and Send Location X Minutes
if (locationData != null) {
Intent intent = new Intent("GPSLocationUpdates");
intent.putExtra("Latitude", "" + locationData.getLatitude());
intent.putExtra("Longitude", "" + locationData.getLongitude());
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
Log.w("==>UpdateLocation<==", "" + String.format("%.6f", locationData.getLatitude()) + "," +
String.format("%.6f", locationData.getLongitude()));
Log.w("Service Send Location", "BGS >> Location Updated");
}
if (handlerSendLocation != null && runnableSendLocation != null)
handlerSendLocation.postDelayed(runnableSendLocation, TIME_INTERVAL_GET_LOCATION);
}
};
#Override
public void onConnected(#Nullable Bundle bundle) {
if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
FusedLocationProviderClient mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
mFusedLocationClient.requestLocationUpdates(mLocationRequest, new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
locationData = locationResult.getLastLocation();
}
}, null);
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
if (connectionResult.hasResolution() && mContext instanceof Activity) {
try {
Activity activity = (Activity) mContext;
connectionResult.startResolutionForResult(activity, CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (Exception e) {
e.printStackTrace();
}
} else {
Log.i("", "Location services connection failed with code " + connectionResult.getErrorCode());
}
}
#Override
public void onLocationChanged(Location location) {
Log.w("==>UpdateLocation<==", "" + String.format("%.6f", location.getLatitude()) + "," + String.format("%.6f", location.getLongitude()));
locationData = location;
}
#Override
public void onDestroy() {
if (handlerSendLocation != null)
handlerSendLocation.removeCallbacks(runnableSendLocation);
Log.w("Service Update Info", "BGS > Stopped");
stopSelf();
super.onDestroy();
}
}
Declare this service in android manifest file like below
<service
android:name=".ServiceLocation"
android:enabled="true"
android:exported="true" />
you can start service from activity using this code
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ContextCompat.startForegroundService(MainActivity.this, new Intent(MainActivity.this, ServiceLocation.class));
} else {
startService(new Intent(MainActivity.this, ServiceLocation.class));
}
Related
I am implementing location tracker from Android app by using foreground service.
The expectation is the foreground service should run even
when app is removed from recent open apps.
When app is in open/foreground.
When app is in background i.e. app is still open but went to background
The case 2 & 3 are working fine but case 1 is working weirdly.
In case 1, sometimes foreground service is getting restarted (notification is going off and coming back) after few seconds i.e. 1 to 3 seconds.
In some other times it is never restarted.
I want the foreground service to never go off. In short, I want it like whatsapp location tracking. The whatsapp tracking icon never goes off when the app is closed.
Please give any pointers on what else I am missing
Activity class
public void enableTracking(String planId, JSONArray trackList, CallbackContext callbackContext) {
Log.i(TAG,"In enableTracking");
Intent intent = new
Intent(cordova.getActivity().getApplicationContext(),LocationTracker.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
cordova.getActivity().startForegroundService(intent);
callbackContext.success("Location Tracking is enabled");
} else {
callbackContext.error("Build version is less than OREO");
}
}
public void disableTracking(CallbackContext callbackContext) {
Log.i(TAG,"In disableTracking");
Intent intent = new Intent(cordova.getActivity().getApplicationContext(),LocationTracker.class);
cordova.getActivity().stopService(intent);
callbackContext.success("Location Tracking is disabled");
}
Service class
public class LocationTracker extends Service {
private final IBinder mBinder = new MyBinder();
private static final String CHANNEL_ID = "2";
private static final String TAG = "LocationTracker";
private FusedLocationProviderClient mFusedLocationClient;
RequestQueue mRequestQueue;
public LocationTracker() {
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
Log.i(TAG, "onTaskRemoved");
super.onTaskRemoved(rootIntent);
}
#Override
public void onCreate() {
super.onCreate();
buildNotification();
// logic to start location tracking
}
#Override
public void onDestroy() {
super.onDestroy();
// logic to stop tracking
}
private void fetchAndSendLocation() {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
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) {
Log.e(TAG, "No permission to fetch location");
return;
}
// mFusedLocationClient.getCurrentLocation()
Task fetchLocTask = mFusedLocationClient.getLastLocation();
fetchLocTask.addOnSuccessListener(new OnSuccessListener() {
#Override
public void onSuccess(Object o) {
Location loc = (Location) o;
if (loc != null) {
Log.i(TAG, "Lat " + loc.getLatitude() + " lon " + loc.getLongitude() + " date " + (new Date()).toString());
postLocation(loc);
}
}
});
}
private void buildNotification() {
String stop = "stop";
PendingIntent broadcastIntent = PendingIntent.getBroadcast(
this, 0, new Intent(stop), PendingIntent.FLAG_UPDATE_CURRENT);
// Create the persistent notification
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(getString(R.string.app_name))
.setContentText("Location tracking is working")
.setOngoing(true)
.setContentIntent(broadcastIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, getString(R.string.app_name),
NotificationManager.IMPORTANCE_DEFAULT);
channel.setShowBadge(false);
channel.setDescription("Location tracking is in progress");
channel.setSound(null, null);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.createNotificationChannel(channel);
}
startForeground(1, builder.build());
}
public class MyBinder extends Binder {
public LocationTracker getService() {
return LocationTracker.this;
}
}
}
AndroidManifest.xml
<service android:enabled="true" android:exported="true" android:foregroundServiceType="location" android:name=".LocationTracker" />
Using LocationManager as in code below has solved this similar situation for me.
public class MyLocationService extends Service {
private static final String TAG = "MyLocationService";
private LocationManager mLocationManager = null;
private static final int LOCATION_INTERVAL = 1000;
private static final float LOCATION_DISTANCE = 10f;
private class LocationListener implements android.location.LocationListener {
Location mLastLocation;
public LocationListener(String provider) {
Log.e(TAG, "LocationListener " + provider);
mLastLocation = new Location(provider);
}
#Override
public void onLocationChanged(Location location) {
Log.e(TAG, "onLocationChanged: " + location);
mLastLocation.set(location);
}
#Override
public void onProviderDisabled(String provider) {
Log.e(TAG, "onProviderDisabled: " + provider);
}
#Override
public void onProviderEnabled(String provider) {
Log.e(TAG, "onProviderEnabled: " + provider);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.e(TAG, "onStatusChanged: " + provider);
}
}
LocationListener[] mLocationListeners = new LocationListener[]{
new LocationListener(LocationManager.PASSIVE_PROVIDER)
};
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onCreate() {
Log.e(TAG, "onCreate");
initializeLocationManager();
try {
mLocationManager.requestLocationUpdates(
LocationManager.PASSIVE_PROVIDER,
LOCATION_INTERVAL,
LOCATION_DISTANCE,
mLocationListeners[0]
);
} catch (java.lang.SecurityException ex) {
Log.i(TAG, "fail to request location update, ignore", ex);
} catch (IllegalArgumentException ex) {
Log.d(TAG, "network provider does not exist, " + ex.getMessage());
}
}
#Override
public void onDestroy() {
Log.e(TAG, "onDestroy");
super.onDestroy();
if (mLocationManager != null) {
for (int i = 0; i < mLocationListeners.length; i++) {
try {
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) {
return;
}
mLocationManager.removeUpdates(mLocationListeners[i]);
} catch (Exception ex) {
Log.i(TAG, "fail to remove location listener, ignore", ex);
}
}
}
}
private void initializeLocationManager() {
Log.e(TAG, "initializeLocationManager - LOCATION_INTERVAL: "+ LOCATION_INTERVAL + " LOCATION_DISTANCE: " + LOCATION_DISTANCE);
if (mLocationManager == null) {
mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
}
}
}
You could modify this to suit your need.
I am making an application that fetch last known location when user clicked power key two times. I am using foreground service to register the broadcast receiver and for location I am using fusedlocationproviderclient. The user can fetch the location while app is in background. My problem is I am only able to fetch location for one time only. Second time location is null. How can I solve it?
Note:
It is working fine in android 7 version.
Service:
public class ScreenOnOffBackgroundService extends Service {
private ScreenOnOffReceiver screenOnOffReceiver = null;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
createNotificationChannel();
Intent mainIntent = new Intent(this, DashboardActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,mainIntent, 0);
Notification notification = new NotificationCompat.Builder(this,"safetyId")
.setContentTitle("Safety Service")
.setContentText("Press power key to send alert")
.setSmallIcon(R.drawable.android)
.setContentIntent(pendingIntent)
.build();
startForeground(1,notification);
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
// Create an IntentFilter instance.
IntentFilter intentFilter = new IntentFilter();
// Add network connectivity change action.
intentFilter.addAction("android.intent.action.SCREEN_ON");
// Set broadcast receiver priority.
intentFilter.setPriority(100);
screenOnOffReceiver = new ScreenOnOffReceiver();
HandlerThread broadcastHandlerThread = new HandlerThread("SafetyThread");
broadcastHandlerThread.start();
Looper looper = broadcastHandlerThread.getLooper();
Handler broadcastHandler = new Handler(looper);
registerReceiver(screenOnOffReceiver,intentFilter,null,broadcastHandler);
}
private void createNotificationChannel() {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ){
NotificationChannel channel = new NotificationChannel(
"safetyId",
"Safety Service",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel);
}
}
#Override
public void onDestroy() {
stopForeground(true);
stopSelf();
// Unregister screenOnOffReceiver when destroy.
if(screenOnOffReceiver!=null)
{
unregisterReceiver(screenOnOffReceiver);
}
}
}
Broadcast Receiver:
public class ScreenOnOffReceiver extends BroadcastReceiver {
private int count = 0;
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_SCREEN_ON.equals(action) || Intent.ACTION_SCREEN_OFF.equals(action)) {
count++;
if (count == 2) {
count = 0;
DashboardActivity.getInstance().getLastLocation();
}
}
}
}
Dashboard Activity:
public class DashboardActivity extends AppCompatActivity {
public Button btnAlert;
private static DashboardActivity instance;
private final static int REQUEST_CODE = 123;
private FusedLocationProviderClient locationProviderClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dashboard);
instance = this;
registerService();
btnAlert = findViewById(R.id.btnAlert);
locationProviderClient = LocationServices.getFusedLocationProviderClient(this);
btnAlert.setOnClickListener(view -> getLastLocation());
}
public static DashboardActivity getInstance(){
return instance;
}
public void registerService(){
if(!foregroundServiceRunning()){
Intent backgroundService = new Intent(this, ScreenOnOffBackgroundService.class);
ContextCompat.startForegroundService(this,backgroundService);
}
}
public boolean foregroundServiceRunning(){
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for(ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)){
if(ScreenOnOffBackgroundService.class.getName().equals(service.service.getClassName())){
return true;
}
}
return false;
}
#SuppressLint("MissingPermission")
public void getLastLocation() {
// check if permissions are given
if (checkPermissions()) {
// check if location is enabled
if (isLocationEnabled()) {
locationProviderClient.getLastLocation().addOnCompleteListener(task -> {
Location location = task.getResult();
if (location == null) {
requestNewLocationData();
} else {
Toast.makeText(this, "Latitude: "+location.getLatitude(), Toast.LENGTH_LONG).show();
}
});
} else {
Toast.makeText(this, "Please turn on your location", Toast.LENGTH_LONG).show();
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
} else {
requestPermissions();
}
}
private boolean checkPermissions() {
return ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
private void requestPermissions() {
String[] permissionArray = new String[]{
android.Manifest.permission.ACCESS_COARSE_LOCATION,
android.Manifest.permission.ACCESS_FINE_LOCATION,};
ActivityCompat.requestPermissions(this, permissionArray, REQUEST_CODE);
}
#SuppressLint("MissingPermission")
private void requestNewLocationData() {
LocationRequest mLocationRequest = LocationRequest.create()
.setInterval(100)
.setFastestInterval(3000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setMaxWaitTime(100).setNumUpdates(1);
locationProviderClient = LocationServices.getFusedLocationProviderClient(this);
locationProviderClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
}
private final LocationCallback mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
Location mLastLocation = locationResult.getLastLocation();
}
};
private boolean isLocationEnabled() {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
#Override
public void
onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
getLastLocation();
}
}
if (requestCode == 0) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
notifyPolice();
}
}
}
}
First off- DashboardActivity.getInstance()- NEVER DO THIS. You're assuming there's exactly 1 instance of an activity at all times. That's wrong. There can be 0. There can be 2. You can't make an activity a singleton. In addition, this always creates a memory leak. NEVER store an Activity in a static variable, this is always a memory leak. It's also (due to the first fact) wrong because it can point to the wrong instance of an Activity.
Secondly- you're using getLastLocation. Don't do that. That function is meant for optimization and will usually return null (I know the docs say the opposite. The docs there have always been wrong.) If you need the location, request it instead. getLastLocation should only be used to get a quick result optimisticly before requesting location updates.
Thirdly- your call to requestNewLocation is passing in a location handler that does nothing. It isn't even updating mLastLocation because that's a method level variable and not a class one.
Fourthly- did you read the new rules for background location processing in ANdroid 12? https://proandroiddev.com/android-12-privacy-changes-for-location-55ffd8c016fd
Those are just the major mistakes, not smaller things that make me go "huh?". With the best of intentions here- this code needs major refactoring. It feels like someone who didn't really understand Android cobbled it together from a dozen examples he didn't understand. If I were you I'd start by simplifying the concept- do one thing, understand it, and then do another. You're overreaching your abilities at the moment doing this all at once, and you'll be better off learning one thing at a time.
This question already has answers here:
How to request Location Permission at runtime
(8 answers)
Closed 1 year ago.
The code below does not work when the application is minimized or closed and doesn't return the current location.
For example, locationCallback only works once and does not work after the app is minimized.
It should be noted that this service has been added to the manifest. It works in the video that I saw on YouTube YouTube Link
public class UpdateLocationService extends Service {
static final int LOCATION_SERVICE_id = 175;
static final String ACTION_START_LOCATION_SERVICE = "startLocationService";
static final String ACTION_STOP_LOCATION_SERVICE = "stopLocationService";
private LocationCallback locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null && locationResult.getLastLocation() != null) {
double lat = locationResult.getLastLocation().getLatitude();
double lng = locationResult.getLastLocation().getLongitude();
Log.d(TAG, lat + ", " + lng);
}
super.onLocationResult(locationResult);
}
};
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#RequiresApi(api = Build.VERSION_CODES.O)
private void startLocationService() {
LocationRequest locationRequest = new LocationRequest();
locationRequest.setInterval(3000);
locationRequest.setFastestInterval(2000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
LocationServices.getFusedLocationProviderClient(this).requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper());
startForeground(LOCATION_SERVICE_id, builder.build());
}
private void stopLocationService() {
LocationServices.getFusedLocationProviderClient(this);
stopForeground(true);
stopSelf();
}
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
String action = intent.getAction();
if (action != null)
if (action.equals(ACTION_START_LOCATION_SERVICE)){
startLocationService();
}else if (action.equals(ACTION_STOP_LOCATION_SERVICE)){
stopLocationService();
}
}
return super.onStartCommand(intent, flags, startId);
}
}
Starting background service has been restricted after Android O https://developer.android.com/about/versions/oreo/background. If you still what to get a location in the background, please consider WorkManger and Foreground services
I have a location service:
public class LocationService extends Service implements Serializable {
public static final String TAG = "LocationService";
private LocationListener locationListener;
private LocationManager locationManager;
public static boolean locationUpdateSent = false;
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void onCreate() {
super.onCreate();
startMyOwnForeground();
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationListener = new LocationListener() {
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void onLocationChanged(Location location) {
buildLocationEvent(location);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
Intent i = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
};
locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#RequiresApi(api = Build.VERSION_CODES.O)
private void startMyOwnForeground(){
String NOTIFICATION_CHANNEL_ID = "LocationChannel";
String channelName = "Location Service";
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_HIGH);
chan.setLightColor(Color.GRAY);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert manager != null;
manager.createNotificationChannel(chan);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
Notification locNotification = notificationBuilder.setOngoing(true)
.setContentTitle("Location is running in background")
.setPriority(NotificationManager.IMPORTANCE_HIGH)
.setCategory(Notification.CATEGORY_SERVICE)
.setSmallIcon(android.R.drawable.ic_menu_mylocation)
.build();
startForeground(1, locNotification);
}
#Override
public void onDestroy() {
super.onDestroy();
if(locationManager != null){
locationManager.removeUpdates(locationListener);
}
stopSelf();
stopForeground(true);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#RequiresApi(api = Build.VERSION_CODES.O)
public void buildLocationEvent(Location location){
//Do Something
}
}
This works fine on Pixel 3A and on a second Pixel, however it does not work on a galaxy S10, A5 and a Pixel XL. Has anyone any experience of any restrictions which would stop this happening? I know it's not much to go on but hopefully if you have seen this behaviour before you might be able to point me in the right direction.
use google fusedlocation client
public class fusedLocation {
Context act;
FusedLocationProviderClient mFusedLocationClient;
Location myLocation=null;
static final int REQUEST_PERMS = 1;
public interface LocationChangListener{
void OnlocationChanged(Location current_location);
}
LocationChangListener main_handler=new LocationChangListener() {
#Override
public void OnlocationChanged(Location current_location) {
}
};
public fusedLocation(final Activity act,LocationChangListener handler_) {
this.act = act;
this.main_handler=handler_;
mFusedLocationClient=LocationServices.getFusedLocationProviderClient(act);
final String permissions[] = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
if (ActivityCompat.checkSelfPermission(act, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
update_tm.schedule(new TimerTask() {
#Override
public void run() {
act.runOnUiThread(new Runnable() {
#Override
public void run() {
getLastLocation();
}
});
}
},100,10000);
} else {
ActivityCompat.requestPermissions(act, permissions, REQUEST_PERMS);
}
}
Timer update_tm=new Timer();
private void getLastLocation() {
mFusedLocationClient.getLastLocation().addOnCompleteListener(new OnCompleteListener<Location>() {
#Override
public void onComplete(#NonNull Task<Location> task) {
Location location = task.getResult();
if (location == null) {
requestNewLocationData();
Log.e("Main", " location is null men");
} else {
Log.e("my coords==> ", "lats " + location.getLatitude() + " longs " + location.getLongitude());
main_handler.OnlocationChanged(location);
}
}
});
}
private void requestNewLocationData() {
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(0);
mLocationRequest.setFastestInterval(0);
mLocationRequest.setNumUpdates(1);
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(act);
mFusedLocationClient.requestLocationUpdates(
mLocationRequest, mLocationCallback,
Looper.myLooper()
);
}
private LocationCallback mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
Location mLastLocation = locationResult.getLastLocation();
Log.e("my refreshed coords==> ", "lats " + mLastLocation.getLatitude() + " longs " + mLastLocation.getLongitude());
main_handler.OnlocationChanged(mLastLocation);
}
};
}
Use the class as below
fusedLocation fusedLocation = new fusedLocation(your_context, new fusedLocation.LocationChangListener() {
#Override
public void OnlocationChanged(Location current_location) {
//Do as you please with the location
Log.e("Position ","mypos_lat "+current_location.getLatitude()+" <==> mypos_long "+current_location.getLongitude());
}
});
I've tried calling this Service in two different ways, but it didn't seem to work.
The first way was:
startService(new Intent(getBaseContext(), LocationService.class));
for which I get an error saying `
Caused by: `java.lang.IllegalStateException: GoogleApiClient is not connected yet.
Then I tried this:
Intent serviceIntent = new Intent();
serviceIntent.setAction("com.parseapp.eseen.eseen.service.LocationService");
startService(serviceIntent);
Also it didn't work, in contrary absolutely nothing happens, nothing shows up in logcat. Can anyone help?
Here's the whole code:
LocationService.class
public class LocationService extends Service implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
// LogCat tag
private static final String TAG = LocationService.class.getSimpleName();
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 1000;
private Location mLastLocation;
// Google client to interact with Google API
private GoogleApiClient mGoogleApiClient;
// boolean flag to toggle periodic location updates
private boolean mRequestingLocationUpdates = false;
private LocationRequest mLocationRequest;
// Location updates intervals in sec
private static int UPDATE_INTERVAL = 10000; // 10 sec
private static int FATEST_INTERVAL = 5000; // 5 sec
private static int DISPLACEMENT = 10; // 10 meters
#Override
public void onCreate() {
super.onCreate();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
togglePeriodicLocationUpdates();
}
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FATEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(DISPLACEMENT);
}
private void togglePeriodicLocationUpdates() {
mGoogleApiClient.connect();
if (!mRequestingLocationUpdates) {
mRequestingLocationUpdates = true;
startLocationUpdates();
Log.d(TAG, "Periodic location updates started!");
} else {
mRequestingLocationUpdates = false;
// Stopping the location updates
stopLocationUpdates();
Log.d(TAG, "Periodic location updates stopped!");
}
}
protected void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
}
protected void startLocationUpdates() {
mGoogleApiClient.connect();
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}
#Override
public void onConnected(Bundle arg0) {
createLocationRequest();
}
#Override
public void onConnectionSuspended(int arg0) {
mGoogleApiClient.connect();
}
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = "
+ result.getErrorCode());
}
#Override
public void onLocationChanged(Location location) {
// Assign the new location
mLastLocation = location;
Toast.makeText(getApplicationContext(), "Location changed!",
Toast.LENGTH_SHORT).show();
}
#Override
public boolean stopService(Intent name) {
return super.stopService(name);
}
SearchActivity.class
button = (Button)findViewById(R.id.buttonPressed);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent serviceIntent = new Intent();
serviceIntent.setAction("com.parseapp.eseen.eseen.service.LocationService");
startService(serviceIntent);
}
});
AndroidManifest.xml
<service android:name=".LocationService">
<intent-filter>
<action android:name=".LocationService"> </action>
</intent-filter>
</service>
Your first attempt to start the service using the class name worked:
startService(new Intent(getBaseContext(), LocationService.class));
The exception occurred after the service started executing. Your code cannot use LocationServices until the GoogleApi connection is successful, namely after onConnected() is called. Your code calls connect() multiple times before getting to startLocationUpdates(), but does not wait for onConnected() to be called. That method is the notification you receive when the connection has been made and LocationServices can be used.
This demo code is for an AsyncTask, not a Service, but gives an idea of how the connection processing can be done using a CountDownLatch.
you package name com.parseapp.eseen.eseen
and You are tryng to call using com.parseapp.eseen.eseen.service.LocationService as action but you mentioned in Manifest as .LocationService that means you should call using com.parseapp.eseen.eseen.LocationService
in startLocationUpdates(); you are calling connect again and requesting api before connecting
request for locationupdates from onConnected method
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);