Testing Mock Locations not Working - android

I have written a simple Gps Service. Now I am writing a testcase for testing it. I am trying to send a mock location but the onLocation changed is not getting called in my GpsService location listener.
Here is my GpsService
/**
* returns the binder object that client of this can bind to
*/
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
#Override
public void onCreate() {
super.onCreate();
Log.e("GpsService","StartService");
}
private class MyLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location loc) {
Log.e("GpsService","Location in GpsService"+loc.toString());
if(loc.hasAccuracy() && loc.getAccuracy() <= minAccuracyMeters)
{
if(targetLocation != null)
{
float distance = loc.distanceTo(targetLocation);
Log.e("GpsService ","Location latitude +"+loc.getLatitude()+"longitude "+loc.getLongitude());
if(distance < 5.0)
Toast.makeText(getBaseContext(), "You have reached the target location", Toast.LENGTH_LONG).show();
}
}
}
public void setTargetLocation (Location _location){
targetLocation = _location;
}
/**
* Class for clients to access. Because we know this service always runs in
* the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
GpsService getService() {
return GpsService.this;
}
}
private final IBinder mBinder = new LocalBinder();
#Override
public void onDestroy() {
if(lm != null)
lm.removeUpdates(locationListener);
super.onDestroy();
}
//Setting up for test case
public void setUpProvider(String provider){
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationListener = new MyLocationListener();
lm.requestLocationUpdates(provider,
minTimeMillis,
minDistanceMeters,
locationListener);
}
Now here is my TestCase
public class MockLocationTest extends ServiceTestCase {
private LocationManager locationManager = null;
private static final String MOCK_GPS_PROVIDER = "MOCK_GPS_PROVIDER";
private List<String> data = new ArrayList<String>();
public MockLocationTest(Class<GpsService> serviceClass) {
super(serviceClass);
}
public MockLocationTest() {
super(GpsService.class);
}
#Override
protected void setupService() {
super.setupService();
System.out.println("Service Set Up");
Intent intent = new Intent(getContext(),GpsService.class);
startService(intent);
assertNotNull("The Service should not be null",getService());
System.out.println("Service Started");
}
#Override
protected void setUp() throws Exception {
super.setUp();
}
#MediumTest
public void testBindable() {
Intent startIntent = new Intent();
startIntent.setClass(getContext(), GpsService.class);
IBinder service = bindService(startIntent);
assertNotNull("Bound to service ",service);
getService().setUpProvider(MOCK_GPS_PROVIDER);
Location demo = new Location(MOCK_GPS_PROVIDER);
demo.setLatitude(22.579937);
demo.setLongitude(88.486805);
getService().setTargetLocation(demo);
System.out.println("Test Bindable");
}
#SmallTest
public void testMockData(){
locationManager = (LocationManager) getContext().getSystemService((Context.LOCATION_SERVICE));
locationManager.setTestProviderEnabled(MOCK_GPS_PROVIDER, true);
Location location = new Location(MOCK_GPS_PROVIDER);
location.setLatitude(22.579937);
location.setLongitude(88.486805);
location.setTime(System.currentTimeMillis());
// show debug message in log
// provide the new location
locationManager.setTestProviderLocation(MOCK_GPS_PROVIDER, location);//send mock data
}
#Override
protected void tearDown() throws Exception {
super.tearDown();
}
}
Unfortunately I cant see any log in the onLocationChange callback in the service. The testcase runs successfully.
I have added the following in both my service and testservice's manifest
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
Can anybody help me here
I also tried putting this in one function
#LargeTest
public void testBindable() {
Intent startIntent = new Intent();
startIntent.setClass(getContext(), GpsService.class);
IBinder service = bindService(startIntent);
assertNotNull("Bound to service ",service);
LocationManager locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
locationManager.addTestProvider(MOCK_GPS_PROVIDER, false, false,
false, false, false, false, false, 0, 5);
locationManager.setTestProviderEnabled(MOCK_GPS_PROVIDER, true);
getService().setUpProvider(MOCK_GPS_PROVIDER,locationManager);
Location demo = new Location(MOCK_GPS_PROVIDER);
demo.setLatitude(22.579937);
demo.setLongitude(88.486805);
demo.setTime(System.currentTimeMillis());
getService().setTargetLocation(demo);
Location narkeldanga = new Location(MOCK_GPS_PROVIDER);
narkeldanga.setLatitude(22.578986);
narkeldanga.setLongitude(88.470154);
narkeldanga.setTime(System.currentTimeMillis());
locationManager.setTestProviderLocation(MOCK_GPS_PROVIDER, narkeldanga);
try {
Thread.sleep(10000);
// gracefully handle Thread interruption (important!)
if(Thread.currentThread().isInterrupted())
throw new InterruptedException("");
} catch (InterruptedException e) {
}
locationManager.setTestProviderLocation(MOCK_GPS_PROVIDER, demo);
try {
Thread.sleep(10000);
// gracefully handle Thread interruption (important!)
if(Thread.currentThread().isInterrupted())
throw new InterruptedException("");
} catch (InterruptedException e) {
}
System.out.println("Test Bindable");
}
but to no avail.

This is a problem I and others have encountered in jUnit tests. Namely, testBindable() will run in one thread while your service is running in another. The result is that the location service is still setting up and hasn't even thought about using your callbacks when the test hits the end and jUnit clears everything from memory. I am still looking for a good recipe to follow for structuring such a test, but I can suggest a few things you could try. The simplest is just to put a sleep() in your test to give things time to process in the other threads. For example:
public void testBindable() throws Exception {
Intent startIntent = new Intent();
startIntent.setClass(getContext(), GpsService.class);
IBinder service = bindService(startIntent);
assertNotNull("Bound to service ",service);
getService().setUpProvider(MOCK_GPS_PROVIDER);
Location demo = new Location(MOCK_GPS_PROVIDER);
demo.setLatitude(22.579937);
demo.setLongitude(88.486805);
getService().setTargetLocation(demo);
TimeUnit.SECONDS.sleep(5);
System.out.println("Test Bindable");
}
This approach is not ideal for a number of reasons. 5 seconds (or whatever you put in) may not be enough sometimes or too much time in other cases.
Alternatively, you can use latches or other mechanisms to detect when your callbacks have executed. However, that approach complicates your code with latches (or you can use mutex locks) that are only used by the test and ideally should not be part of the actual application under test.

The value of MOCK_GPS_PROVIDER shouldn't be "flp" ?
http://developer.android.com/training/location/location-testing.html#TestData

Related

is it possible to quit looper in onReceive method in BroadcastReceiver

Using the following code and when onReceive is fired,am getting the following error
Error receiving broadcast Intent { act=com.sample.service.ReminderActivityService flg=0x10 (has extras) }
in com.sample.common.UserActivity$1#41c2b4b0
The problem is this statement Looper.myLooper().quit();
How do I terminate my looper after receiving the broadcast in the code below?
public class UserActivity extends Thread implements
ConnectionCallbacks, OnConnectionFailedListener {
private String TAG;
// Constants that define the activity detection interval
public static final int MILLISECONDS_PER_SECOND = 1000;
public static final int DETECTION_INTERVAL_SECONDS = 30;
public static final int DETECTION_INTERVAL_MILLISECONDS = MILLISECONDS_PER_SECOND * DETECTION_INTERVAL_SECONDS;
IntentService is;
onActivityGot mCallback;
Handler mHandler;
Context mContext;
BroadcastReceiver br;
/*
* Store the PendingIntent used to send activity recognition events
* back to the app
*/
private PendingIntent mActivityRecognitionPendingIntent;
// Store the current activity recognition client
private ActivityRecognitionClient mActivityRecognitionClient;
public UserActivity(UserActivity.onActivityGot ints) {
is = (IntentService) ints;
mContext = is.getApplicationContext();
mHandler = new Handler();
TAG = this.getClass().getSimpleName();
// This makes sure that the container service has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (UserActivity.onActivityGot) ints;
} catch (ClassCastException e) {
throw new ClassCastException(ints.toString()
+ " must implement UserActivity.onActivityGot");
}
Log.i(TAG, "UserActivity constractor fired in activity");
}
#Override
public void run() {
if (servicesConnected()) {
Looper.prepare();
Log.i(TAG, "servicesConnected fired in activity");
/*
* Instantiate a new activity recognition client. Since the
* parent Activity implements the connection listener and
* connection failure listener, the constructor uses "this"
* to specify the values of those parameters.
*/
mActivityRecognitionClient =
new ActivityRecognitionClient(mContext, this, this);
// connect to the service
mActivityRecognitionClient.connect();
br = new BroadcastReceiver() {
#Override
public void onReceive(Context c, Intent i) {
//call calback with data
mCallback.activityKnown(i);
mActivityRecognitionClient.removeActivityUpdates(mActivityRecognitionPendingIntent);
mActivityRecognitionClient.disconnect();
mContext.unregisterReceiver(br);
Looper.myLooper().quit();
}
};
mContext.registerReceiver(br, new IntentFilter("com.sample.service.ReminderActivityService"));
Looper.loop();
}
}
#Override
public void onConnected(Bundle dataBundle) {
Log.i(TAG, "onConnected fired");
/*
* Create the PendingIntent that Location Services uses
* to send activity recognition updates back to this app.
*/
Intent intent = new Intent(
mContext, ReminderActivityService.class);
/*
* Return a PendingIntent that starts the IntentService.
*/
mActivityRecognitionPendingIntent =
PendingIntent.getService(mContext, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
/*
* Request activity recognition updates using the preset
* detection interval and PendingIntent. This call is
* synchronous.
*/
mActivityRecognitionClient.requestActivityUpdates(
DETECTION_INTERVAL_MILLISECONDS,
mActivityRecognitionPendingIntent);
}
#Override
public void onDisconnected() {
// Delete the client
mActivityRecognitionClient = null;
Looper.myLooper().quit();
Log.i(TAG, "onDisconnected fired");
}
#Override
public void onConnectionFailed(ConnectionResult cr) {
mHandler.post(new UiToastCommunicaton(mContext,
is.getResources().getString(R.string.action_connfailed)));
mCallback.activityFail();
Looper.myLooper().quit();
Log.i(TAG, "onConnectionFailed fired");
}
private boolean servicesConnected() {
// Check that Google Play services is available
int resultCode =
GooglePlayServicesUtil.
isGooglePlayServicesAvailable(is.getBaseContext());
if (ConnectionResult.SUCCESS == resultCode) {// If Google Play services is available
// In debug mode, log the status
Log.d("Activity Recognition",
"Google Play services is available.");
// Continue
return true;
} else {// Google Play services was not available for some reason
mHandler.post(new UiToastCommunicaton(mContext,
is.getResources().getString(R.string.gpserv_notfound)));
return false;
}
}
public interface onActivityGot {
public void activityKnown(Intent i);
public void activityFail();
}
}
found a way by storing a handle to the looper in a static variable. view below.
declare the variable
public static Handler looperHandle;
set the variable after preparing looper
Looper.prepare();
looperHandle = new Handler();
since i had instantiated the class in an object i just called
object.looperHandle.getLooper().quit();
am not comfortable with this solution because of using a static variable.
if someone has a better solution please post it here.

How to fix Service Instance Issue?

I am starting a service based on Alarm Manager in every 20 seconds which sends GPS data to my server.
The problem is my heap and allocated heap size goes on increasing. When I analysed the heap dump, I found the number of service instances is equal to the number of calls to startService(). How to avoid this issue?
public class SystemBootListener extends BroadcastReceiver {
// Restart service every 30 seconds
private static final long REPEAT_TIME = 1000 * 10;
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, StartLocationServiceAfterReboot.class);
PendingIntent pending = PendingIntent.getBroadcast(context, 0, PendingIntent.FLAG_UPDATE_CURRENT);
// Start 20 seconds after boot completed - so that all providers are initialized by then
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 20);
// Trigger every 10 seconds
// InexactRepeating allows Android to optimize the energy consumption
AlarmManager service = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
service.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), REPEAT_TIME, pending);
}
}
public class StartLocationServiceAfterReboot extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(AppSettings.isRouteConfigured(context)){
AppSettings.setServiceRunning(context, Boolean.TRUE);
Intent service = new Intent(context, GPSComputationService.class);
context.startService(service);
}
}
}
public class GPSComputationService extends Service {
private static final int MAX_TIME_TO_FETCH_NEW_LOCATION = 8000;
private final IBinder mBinder = new ServiceBinder();
private Timer timerToFetchLocInfoFromProviders = null;
private LocationManager locationManager = null;
private boolean gpsProviderEnabled=false;
private boolean networkProviderEnabled=false;
private int numberOfSatellites = 0;
private GPSData bestKnownLocation = new GPSData();
private TCPWriter tcpWriter ;
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
tcpWriter= new TCPWriter(this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
/*tcpWriter= new TCPWriter(this);*/
computeBestLocation();
return Service.START_STICKY;
}
private void stopGPSComputationService(){
stopSelf();
}
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
public class ServiceBinder extends Binder {
public GPSComputationService getService() {
return GPSComputationService.this;
}
}
public GPSData getBestKnownLocation() {
return bestKnownLocation;
}
public void publishBestKnownLocation(GPSData bestKnownLocation) {
this.bestKnownLocation = bestKnownLocation;
sendBestKnownLocationToNMEAServer();
}
public void sendBestKnownLocationToNMEAServer(){
if(getBestKnownLocation() == null){
stopGPSComputationService();
return;
}
TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.getDeviceId();
NMEAData dataPacketToWrite = new NMEAData(
telephonyManager.getDeviceId(),
getBestKnownLocation().getLatitude(),
getBestKnownLocation().getLongitude(),
getBestKnownLocation().getTimeStamp(),
getBestKnownLocation().getSpeed(),
getBestKnownLocation().getNumberOfSatellites()
);
tcpWriter.sendMessage(NMEAServerTypes.MVT600,
dataPacketToWrite);
stopGPSComputationService();
}
public GPSData computeBestLocation() {
Log.d("#############GPSComputation Status", "Running.......");
try{
if(locationManager==null)
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
//Add status listener for satellite count
locationManager.addGpsStatusListener(gpsStatusListener);
Criteria criteria = new Criteria();
criteria.setSpeedRequired(true);
criteria.setBearingRequired(true);
List<String> providers = locationManager.getProviders(criteria, false);
//Capture if the GPS/Network providers have been disabled.
try{
gpsProviderEnabled=providers.contains(LocationManager.GPS_PROVIDER) &&
locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
}catch(Exception e){
}
try{
networkProviderEnabled=providers.contains(LocationManager.NETWORK_PROVIDER) &&
locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}catch(Exception e){
}
if(!gpsProviderEnabled && !networkProviderEnabled)
return null;
if(gpsProviderEnabled)
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListenerGps);
if(networkProviderEnabled)
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListenerNetwork);
timerToFetchLocInfoFromProviders=new Timer();
timerToFetchLocInfoFromProviders.schedule(new GetLastKnownGoodLocation(), MAX_TIME_TO_FETCH_NEW_LOCATION);
locationManager.removeGpsStatusListener(gpsStatusListener);
//Finally store the data in backend Service
return getBestKnownLocation() ;
}catch(Exception e){
return null;
}
}
LocationListener locationListenerGps = new LocationListener() {
public void onLocationChanged(Location location) {
timerToFetchLocInfoFromProviders.cancel();
publishBestKnownLocation(extractAllGeoInfFromLocation(location));
locationManager.removeUpdates(this);
locationManager.removeUpdates(locationListenerNetwork);
locationManager.removeGpsStatusListener(gpsStatusListener);
gpsStatusListener = null;
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
//listen for gps status changes to capture number of satellites.
GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener() {
#Override
public void onGpsStatusChanged(int event) {
if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS || event == GpsStatus.GPS_EVENT_FIRST_FIX) {
GpsStatus status = locationManager.getGpsStatus(null);
Iterable<GpsSatellite> sats = status.getSatellites();
// Check number of satellites in list to determine fix state
int tempNumberOfSatellites = 0;
for (GpsSatellite sat : sats) {
if(sat.usedInFix())
tempNumberOfSatellites++;
}
numberOfSatellites = tempNumberOfSatellites;
}
}
};
LocationListener locationListenerNetwork = new LocationListener() {
public void onLocationChanged(Location location) {
timerToFetchLocInfoFromProviders.cancel();
publishBestKnownLocation(extractAllGeoInfFromLocation(location));
locationManager.removeUpdates(this);
locationManager.removeUpdates(locationListenerGps);
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
class GetLastKnownGoodLocation extends TimerTask {
#Override
public void run() {
locationManager.removeUpdates(locationListenerGps);
locationManager.removeUpdates(locationListenerNetwork);
Location bestKnownNetworkLocation = null, bestKnownGPSLocation=null;
if(gpsProviderEnabled)
bestKnownGPSLocation=locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if(networkProviderEnabled)
bestKnownNetworkLocation=locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if(bestKnownGPSLocation!=null && bestKnownNetworkLocation!=null){
if(bestKnownGPSLocation.getTime()>bestKnownNetworkLocation.getTime())
publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownGPSLocation));
else
publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownNetworkLocation));
return;
}
if(bestKnownGPSLocation!=null){
publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownGPSLocation));
return;
}
if(bestKnownNetworkLocation!=null){
publishBestKnownLocation(extractAllGeoInfFromLocation(bestKnownNetworkLocation));
return;
}
AppLog.logWarningMsg("Bad luck-NO BEST LOCATION AVAILABLE");
publishBestKnownLocation(null);
}
}
private GPSData extractAllGeoInfFromLocation(Location location){
bestKnownLocation = new GPSData();
bestKnownLocation.setLatitude(location.getLatitude());
bestKnownLocation.setLongitude(location.getLongitude());
bestKnownLocation.setTimeStamp(location.getTime());
bestKnownLocation.setSpeed(location.getSpeed()*3.8);
bestKnownLocation.setNumberOfSatellites(numberOfSatellites);
return bestKnownLocation;
}
}
There is only one instance of service. As per the document
Multiple calls to Context.startService() do result in multiple corresponding calls to onStartCommand()),
But only one service instance can exist.
On startService(), the Android system calls the service's onStartCommand() method. If the service is not already running, the system first calls onCreate(), then calls onStartCommand().
The only thing that can create this kind of scenario is that you have some kind of memory leak.
Your service did it's work and stopped but didn't garbage collected. it probably happen few times and that is why you see many instances of it.
It's hard to find memory leaks but i would suggest you to start from the listeners. check if you unregistered them at the right time.
This link can help you to detect the leak:
https://developer.android.com/studio/profile/am-memory.html
Some tips to improve and simplify your code:
You want to use one shot service to report GPS coordinates. For this purpose IntentService is much better and it runs in a background thread by design.
https://developer.android.com/training/run-background-service/create-service
Use PendingIntent.getService() instead of call StartLocationServiceAfterReboot which just launch other Android component. You can do that immediately. You save one step.
https://developer.android.com/reference/android/app/PendingIntent.html#getService(android.content.Context,%2520int,%2520android.content.Intent,%2520int)
Every time you use a resource (like GPS, Sensor, etc...) you have to also write the release part. As I see, you register listeners to GPS Service but never release (unregister) them.
What does AppSettings.setServiceRunning(context, Boolean.TRUE);? My guess you save this into SharedPreference. This can be compromised when app force-stopped or device restarted or suddenly shut-down. Maybe better way this https://stackoverflow.com/a/5921190/5823014
Avoid to use static on Context, Activity, Service, BroadcastReceiver, Application instance. I'm not see in your code snippet, just a general advice to prevent memory-leaks.

How can I pass ApplicationContext into the function in a new Thread()?

I need to get location information about GPS location every 30 seconds in an infinity loop and send in to a server via HTTP-request. Endless cycle if GPS scanning should be stopped If i get an appropriate response from the server. Service is called DataTransferService, gps scanner is called GPSTracker for this and service . The problem is that I can't get a proper Context for my GPSTracker in my new Thread(new Runnable()).
If i create a ThreadHandler my MainActivity will freeze. In addition, context is also null even if I'm initializing in my service to use later.
Here is my DataTransferService.java
public class DataTransferService extends Service {
final static String LOG_TAG = "---===> service";
private boolean isRunning = false;
private GPSTracker gps;
private double lat;
private double lng;
public void onCreate() {
super.onCreate();
Log.d(LOG_TAG, "onCreate");
}
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(LOG_TAG, "onStartCommand");
if (!isRunning) {
StartLocationService();
isRunning = true;
}
return super.onStartCommand(intent, flags, startId);
}
public void onDestroy() {
isRunning = false;
super.onDestroy();
Log.d(LOG_TAG, "onDestroy");
}
public IBinder onBind(Intent intent) {
Log.d(LOG_TAG, "onBind");
return null;
}
private void StartLocationService(final String login, final String password) {
Thread thread = new Thread(new Runnable() {
public void run() {
Log.d(LOG_TAG, "StartLocationService() started");
while (true) {
//CHECK IF SERVICE IS RUNNING
if (!isRunning) {
stopSelf();
break;
}
//HERE IS THE PROBLEM <----------------
gps = new GPSTracker(getApplicationContext());
//GETTING GPS INFO
if(gps.canGetLocation()){
lat = gps.getLatitude();
lng = gps.getLongitude();
}else{
gps.showSettingsAlert();
}
try {
Log.d(LOG_TAG, String.format("location is: %f; %f", lat, lng));
//i wanted to send HTTP request to the server here with the gps coordinates
} catch (MalformedURLException e) {
e.printStackTrace();
}
//SERVICE DELAY
try {
TimeUnit.SECONDS.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.start();
}
}
As I wanted to stop the endless loop when user presses "Stop" button I've created bool variable which indicated if the cycle should bee countinued or stopped.
UPDATE:
I added some debug outputs(before my Thread() and inside It) to determine if getApplicationContext() result isreally different and I found out, that all the objects are equal.
I used Log.d(LOG_TAG, getApplicationContext().toString()); before the Thread() and Log.d(LOG_TAG, mApplication.getInstance().getApplicationContext().toString()); inside the Thread(), where mApplication - is my singleton.
Results:
D/---===> service(7264): com.my.program.MyApplication#40ce3ee0
D/---===> service(7264): StartLocationService() started
D/---===> service(7264): com.my.program.MyApplication#40ce3ee0
Here is my GPSTracker.java if you are interested in it: http://pastebin.com/p6e3PGzD
Have you checked why your Activity will be frozen if you use HandlerThread? You can also create a Handler out of your thread, and send data via handler within your thread.
How can I pass ApplicationContext into the function in a new Thread()
You don't need to pass application context as you can access it from anywhere by
Defining android Application class in your codebase.
Just google "define application class android example"
http://developer.android.com/reference/android/app/Application.html
http://www.devahead.com/blog/2011/06/extending-the-android-application-class-and-dealing-with-singleton/
MyApplication.instance.getApplicationContext();
should be what you want. (where instance will be the singleton object you will define)

FusedLocationService not aquiring GPS signal in Android

I'm using the new FusedLocationService, but, despite I'm getting latitude and longitude while being indoors, I don't see GPS signal being aquired (small gps point in the notifications bar not appearing).
I'm using the example from here adapted to location service
What I don't understand is why GPS signal is not being searched for despite GPS is enabled (but I'm getting coordinates, I guess I getting those from wifi or cell id)
In my Application class I create a Service (this is a ServicesManager, which in turn creates another service (to retrieve locations). I'm sending as context to LocationClient the ServicesManager as it is a context (because it's a Service).
Thanks in advance. Guillermo.
UPDATE
If I turn off the Use Wireless Network option in location services on the phone while GPS is enabled I don't get locations at all. So something is happening with the FusedLocationService and the GPS.
I'll add code so it can be better understood
In Application class I'm using the LocalService example from: here
private ServicesManager mBoundService;
private boolean mIsBound;
private ServiceConnection mConnectionToServicesManager = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mBoundService = ((ServicesManager.LocalBinder)service).getService();
servicesManager = mBoundService;
}
public void onServiceDisconnected(ComponentName className) {
mBoundService = null;
}
};
void doBindServiceManagerService() {
bindService(new Intent(this, ServicesManager.class), mConnectionToServicesManager, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
unbindService(mConnectionToServicesManager);
mIsBound = false;
}
}
Then ServicesManager extends Service and in the constructor I'm writing this:
fusedLocationService = new FusedLocationService(this);
Then I call to:
fusedLocationService.startListeningLocationUpdates(this);
This is the implementation of startListeningLocationUpdates in FusedLocationService class
public boolean startListeningLocationUpdates(Context context) {
if (!GdpTesisApplication.IsGooglePlayServicesAvailable) {
return false;
}
mDetectionRequester.requestUpdates();
FusedLocationService.IsServiceRunning = true;
return true;
}
And requestUpdates() tries to connecto to GooglePlayServices
private void requestConnection() {
getFusedLocationClient().connect();
}
#Override
public void onConnected(Bundle arg0) {
continueRequestLocationUpdates();
}
private void continueRequestLocationUpdates() {
locationrequest = LocationRequest.create();
locationrequest.setInterval(LocationUtils.DETECTION_INTERVAL_MILLISECONDS);
getFusedLocationClient().requestLocationUpdates(locationrequest, createRequestPendingIntent());
}
private PendingIntent createRequestPendingIntent() {
if (null != getRequestPendingIntent()) {
return mFusedLocationPendingIntent;
} else {
Intent intent = new Intent(mContext, FusedLocationIntentService.class);
PendingIntent pendingIntent = PendingIntent.getService(mContext, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
setRequestPendingIntent(pendingIntent);
return pendingIntent;
}
}
Finally I have an IntentService which onHandleIntent extracts the location and shows it with:
Location location = intent.getParcelableExtra(LocationClient.KEY_LOCATION_CHANGED);
I don't know why GPS is not working. Any idea?
Take a look here:
http://developer.android.com/reference/com/google/android/gms/location/LocationRequest.html#setPriority%28int%29
You didn't set a priority for your LocationRequest. Try with PRIORITY_HIGH_ACCURACY.

I can't stop my Service (update my location) on my android app!

I've implemented a Service which update my current location and send it to my Server.
I only use with a ToggleButton: startService() to call the service and stopService() to stop it.
I've seen on the logCat that the service continue to run after calling stopService because when I restart the service, it update two time (three...or four..) my location.
My code:
Service: Geolocalisation.java
public class Geolocalisation extends Service{
private LocationManager locationManager;
//private String locationProvider = LocationManager.NETWORK_PROVIDER;
private String locationProvider = LocationManager.NETWORK_PROVIDER;
#Override
public void onCreate(){
System.out.println("Service en cours !!");
//Recuperation Location
String locationContext = Context.LOCATION_SERVICE;
locationManager = (LocationManager) getSystemService(locationContext);
if (locationManager != null && locationProvider != null) {
majCoordonnes();
locationManager.requestLocationUpdates(locationProvider, 10000, 0, new MajListener());
}
}
#Override
public void onStart(Intent intent, int StartId){
System.out.println("Service commence !!");
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("geo", true);
editor.commit();
}
#Override
public void onDestroy(){
System.out.println("Service détruit !!");
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("geo", false);
editor.commit();
}
#Override
public IBinder onBind(Intent arg0){
return null;
}
public void majCoordonnes() {
StringBuilder stringBuilder = new StringBuilder("Fournisseur :");
stringBuilder.append("\n");
stringBuilder.append(locationProvider);
stringBuilder.append(" : ");
Location location = locationManager.getLastKnownLocation(locationProvider);
if (location != null) {
double latitude = location.getLatitude();
double longitude = location.getLongitude();
String lat = String.valueOf(latitude);
String lon = String.valueOf(longitude);
stringBuilder.append(latitude);
stringBuilder.append(", ");
stringBuilder.append(longitude);
//Send location to server
new sendLocation().execute(lat, lon);
System.out.println("Localisation: "+ lat +" "+lon );
} else {
stringBuilder.append("Non déterminée");
}
//Log.d("MaPositionMaj", stringBuilder.toString());
}
/**
* Ecouteur utilisé pour les mises à jour des coordonnées
*/
class MajListener implements android.location.LocationListener {
public void onLocationChanged(Location location) {
majCoordonnes();
System.out.println("Update geo!");
}
public void onProviderDisabled(String provider){
}
public void onProviderEnabled(String provider){
}
public void onStatusChanged(String provider, int status, Bundle extras){
}
};
My Main.java which call and destroy the service by ToggleButton:
intentGeo = new Intent().setClass(this,Geolocalisation.class);
Boolean boolLog = preferences.getBoolean("geo", false);
final ToggleButton toggleAge = (ToggleButton) findViewById(R.id.ToggleGeo);
//Check ToggleButton if the service is already running
if( boolLog != true){
try{
toggleAge.setChecked(false);
}catch (Exception e){
System.out.println("Service Error");
}
} else {
toggleAge.setChecked(true);
}
//Activer ou désactivé le service de géolocalisation
toggleAge.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// Perform action on clicks
if (toggleAge.isChecked()) {
try{
startService(intentGeo);
System.out.println("Turn ON");
}catch (Exception e){
System.out.println("Service Error");
}
} else {
try{
stopService(intentGeo);
System.out.println("Turn OFF");
}catch (Exception e){
System.out.println("Service Error");
}
}
}
});
Thanks for your help !
PS I use Sharedpreference to determinate if Service is running or not. But if the service crash, it will occures a problem. How can I check the state of my Service?
You shouldn't need to start and stop the service yourself. You can bind your activity to the service and then use methods on your service to stop/start it.
To bind to a service, you need to use something like this from your activity, probably in onCreate:
Intent serviceIntent = new Intent();
serviceIntent.setClass(this, YourService.class);
bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE);
There are some other boilerplate things you will need to do, described here. Once your activity is bound to the service, you can then stop and start it using methods on your service class via a concrete object reference.
Just be sure to unbind from the service when your activity is destroyed!
unbindService(connection);
In your onDestroy function from Geolocalisation.java you are not ending the Listener, you are simply changing the variable that your program checks to see if the service is running or not. You could add code here to stop the location listener from running any further.
locationManager.removeUpdates(locationProvider);
should do the trick.
To stop updating the server maybe you should overwrite the stopService function with the stopping code?
#Override
public stopService(Intent service)
{
super.stopService();
// code to stop updating server
}

Categories

Resources