I have a jobScheduler with fusedLocationApi provider. It works alright but once a while it gives null value for a no. of time (6-7 times in a sequence). I tried onLocationChanged() and LocationServices.FusedLocationApi.requestLocationUpdates(), both gives null values at same time. How can I improve it? I have set high accuracy or Gps,wifi and mobile networks as locating method in device setting. thanks in advance.
One more thing, 80% of the null value are received when there is no wifi. I think Fused Api should have worked well without wifi as well Since there is gps available, isn't it?
Main class
public class LiveTrack extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live_track);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
jobScheduler = (JobScheduler)getSystemService(JOB_SCHEDULER_SERVICE);
ComponentName jobService =
new ComponentName(getPackageName(), MyJobService.class.getName());
JobInfo jobInfo =
new JobInfo.Builder(MYJOBID, jobService).setPeriodic(15 * 60 * 1000L)
.setExtras(bundle)
.build();
int jobId = jobScheduler.schedule(jobInfo);
if(jobScheduler.schedule(jobInfo)>0){
Log.e("status","running");
}else{
Log.e("status","failed");
}
}
}
JobService class with fused Api Provider
public class MyJobService extends JobService
implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener
, LocationListener {
private GoogleApiClient mGoogleApiClient;
LocationRequest mLocationRequest;
private Location mLastLocation;
public static String latitude;
public static String latitudeIfNull;
public static String longitude;
public static String longitudeIfNull;
#Override
public boolean onStartJob(JobParameters jobParameters) {
setUpLocationClientIfNeeded();
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(30000);
mLocationRequest.setFastestInterval(30000);
return false;
}
#Override
public boolean onStopJob(JobParameters jobParameters) {
Toast.makeText(this,
"App has stopped working. Please open the app again. Thankyou",
Toast.LENGTH_LONG).show();
return false;
}
#Override
public void onConnected(#Nullable Bundle bundle) {
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;
}
LocationServices.FusedLocationApi.requestLocationUpdates(this.mGoogleApiClient,mLocationRequest, this);
createLocationRequest();
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
private void setUpLocationClientIfNeeded()
{
if(mGoogleApiClient == null)
buildGoogleApiClient();
}
protected synchronized void buildGoogleApiClient() {
this.mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
this.mGoogleApiClient.connect();
}
#Override
public void onLocationChanged(Location location) {
latitudeIfNull = location.getLatitude() + "";
longitudeIfNull = location.getLongitude() + "";
Log.e("gps longitude",longitudeIfNull);
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(60000);
mLocationRequest.setFastestInterval(50000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
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;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, new LocationCallback() {
#Override
public void onLocationResult(final LocationResult locationResult) {
latitude = locationResult.getLastLocation().getLatitude() + "";
longitude = locationResult.getLastLocation().getLongitude() + "";
Log.i("latitude ", latitude + "");
Log.i("longitude ", longitude + "");
}
#Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
Log.i("onLocationAvailability", "onLocationAvailability: isLocationAvailable = " + locationAvailability.isLocationAvailable());
}
}, null);
}
}
.
Try this
Create a background service class like this
public class LocationBackGroundService extends Service implements LocationListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = "LocationBackGroundService";
private static final long INTERVAL = 100;
private static final long FASTEST_INTERVAL = 100;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mCurrentLocation;
Context mCOntext;
public void LocationBackGroundService(Context mContext) {
this.mCOntext = mContext;
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
mGoogleApiClient.connect();
}
#Override
public void onCreate() {
super.onCreate();
if (!isGooglePlayServicesAvailable()) {
// finish();
}
createLocationRequest();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
if (mGoogleApiClient.isConnected()) {
startLocationUpdates();
}
}
private boolean isGooglePlayServicesAvailable() {
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (ConnectionResult.SUCCESS == status) {
return true;
} else {
return false;
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onConnected(Bundle bundle) {
startLocationUpdates();
}
protected void startLocationUpdates() {
PendingResult<Status> pendingResult = LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
Log.d(TAG, "Location update started ..............: ");
}
#Override
public void onConnectionSuspended(int i) {
Toast.makeText(this, "OnConnection Suspended", Toast.LENGTH_SHORT).show();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Toast.makeText(this, "OnConnection Failed", Toast.LENGTH_SHORT).show();
}
#Override
public void onLocationChanged(Location location) {
if (null != mCurrentLocation) {
mCurrentLocation = location;
String lat = String.valueOf(mCurrentLocation.getLatitude());
String lng = String.valueOf(mCurrentLocation.getLongitude());
}
}
}
And call when activity starts like this
startService(new Intent(this, yourBackgroundServiceName.class));
and in menifest
<service android:name=".yourBackgroundServiceName"></service>
and don;t forget to add run time permissions before stating a service
I need to update the location to the server when the user travel from one place to another place. We can update when my app opens. How can i update location even when the user not opening app for a long time?
Use service.
public class MyService extends Service implements LocationListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = "MyService";
private static final int UPDATE_INTERVAL = 5000;
private static final int FASTEST_INTERVAL = 3000;
private GoogleApiClient client;
private LocationRequest locationRequest;
private String lat, lon;
#Override
public void onConnected(#Nullable Bundle bundle) {
if (Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP_MR1) {
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) ==
PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) ==
PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(client,
locationRequest, this);
}
}else {
LocationServices.FusedLocationApi.requestLocationUpdates(client,
locationRequest, this);
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
#Override
public void onLocationChanged(Location location) {
Log.i(TAG, "onLocationChanged: " + location);
lat = String.valueOf(location.getLatitude());
lon = String.valueOf(location.getLongitude());
updateLocation();
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onCreate() {
Log.d(TAG, "onCreate");
preferences = getSharedPreferences(AppConfig.PREF, MODE_PRIVATE);
locationRequest = new LocationRequest();
locationRequest.setInterval(UPDATE_INTERVAL);
locationRequest.setFastestInterval(FASTEST_INTERVAL);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
buildGoogleApiClient();
}
protected synchronized void buildGoogleApiClient() {
client = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
client.connect();
}
#Override
public void onDestroy() //remove location update
{
Log.d(TAG, "onDestroy");
super.onDestroy();
if (client != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(client, this);
client.disconnect();
}
}
private void updateLocation(){
StringRequest stringRequest = new StringRequest(Request.Method.POST, AppConfig.URL_LOCATIONUPDATE, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show();
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(), error.toString(), Toast.LENGTH_LONG).show();
}
}) {
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("currLat",lat );
params.put("currLon",lon );
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
requestQueue.add(stringRequest);
}
}
Call this service from your activity.
Intent serviceIntent = new Intent(this, MyService.class);
startService(serviceIntent);
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 have a service that when it creates and starts, initiates prerequisites of using FusedLocationAPI . buildGoogleApiClient() and createLocationRequest() with parameters that initiated by my getConfig() method from database.
This solution works great and accurate with parameters like:
UPDATE_INTERVAL= 10000 (10 sec) , FASTEST_INTERVAL= 5000 (5 sec) , DISPLACEMENT= 10 ( m )
But I need to set interval up to 5 minutes. So when i set prameters like :
UPDATE_INTERVAL= 300000 (5 min) , FASTEST_INTERVAL= 180000 (3 min) , DISPLACEMENT= 10 ( m )
GPS behaves differently and after 30 seconds stops searching GPS and location notification that blinks, disappears.
And starts searching again after device locked and unlocked or this Service stops and starts again.
Here is my service. Please tell me why searching GPS stops right after 30 seconds.
Thanks in advanece.
public class MainService extends Service implements ConnectionCallbacks,
OnConnectionFailedListener, LocationListener {
private final static String TAG = MainActivity.class.getSimpleName();
private static int UPDATE_INTERVAL;
private static int FASTEST_INTERVAL;
private static int DISPLACEMENT;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
private Location mLastLocation;
public String deviceIMEI;
public boolean isGpsEnabled = false;
DatabaseHelper mDBHelper;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
getDeviceIMEI();
getConfig();
startForeGroundService();
if (checkPlayServices() && checkLocationServices()) {
buildGoogleApiClient();
createLocationRequest();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mGoogleApiClient != null)
mGoogleApiClient.connect();
else {
stopForeground(true);
stopSelf();
}
return (START_NOT_STICKY);
}
#Override
public void onDestroy() {
stopForeground(true);
if (mGoogleApiClient != null)
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
mGoogleApiClient.disconnect();
}
#SuppressWarnings("deprecation")
public void startForeGroundService() {
Notification note = new Notification(
R.drawable.track_notification_alert,
"GPS tracking started ...", System.currentTimeMillis());
Intent i = new Intent();
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pi = PendingIntent.getActivity(this, 0, i, 0);
note.setLatestEventInfo(this, "GPS is active.",
"Now this tablet is under tracking. ", pi);
note.flags |= Notification.FLAG_NO_CLEAR;
startForeground(1337, note);
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setSmallestDisplacement(DISPLACEMENT);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
private boolean checkLocationServices() {
LocationManager lm = (LocationManager) getApplicationContext()
.getSystemService(LOCATION_SERVICE);
isGpsEnabled = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
return isGpsEnabled;
}
private boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil
.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
return false;
}
return true;
}
#Override
public void onConnected(Bundle arg0) {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
if (Globals.isSatelliteFix && Globals.isGPSEnable)
setPoint();
}
#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) {
mLastLocation = location;
if (Globals.isSatelliteFix && Globals.isGPSEnable)
setPoint();
}
private void setPoint() {
mDBHelper = new DatabaseHelper(getApplicationContext());
mLastLocation = LocationServices.FusedLocationApi
.getLastLocation(mGoogleApiClient);
if (mLastLocation != null) {
double latitude = mLastLocation.getLatitude();
double longitude = mLastLocation.getLongitude();
try {
Point p = new Point();
p.setId(UUID.randomUUID().toString());
p.setIMEI(deviceIMEI);
p.setLatitude(String.valueOf(latitude));
p.setLongitude(String.valueOf(longitude));
p.setTimeStamp(createTimeStamp());
long result = mDBHelper.addPoint(p);
if (result != -1) {
Log.i(TAG, "Insertion Successfull With RowId: " + result);
} else
Log.e(TAG, "Insertion Error");
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "Insertion Error: " + e.getMessage());
}
}
}
public String createTimeStamp() {
String strTimeStamp = new SimpleDateFormat("yyyy-MM-dd_kk:mm:ss")
.format(new Date());
return strTimeStamp;
}
public void getDeviceIMEI() {
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
deviceIMEI = telephonyManager.getDeviceId();
}
public long getTimeInMiliSeconds() {
Calendar calendar = Calendar.getInstance();
Date date = calendar.getTime();
return date.getTime();
}
public void getConfig() {
Config config = new Config();
mDBHelper = new DatabaseHelper(getApplicationContext());
config = mDBHelper.getConfig();
UPDATE_INTERVAL = config.getUpdateInterval();
FASTEST_INTERVAL = config.getFastestInterval();
DISPLACEMENT = config.getSmallestDisplacement();
}
}
I am building an app to help keep up with your bar tab while you are out on the town. I have a feature where the user can set a proximity alarm (a Geofence) to remind them to close their tab if they leave the bar without closing out. First the map is shown, then a marker is put at the user's location, and then a 100 meter geofence is displayed around the marker. The user's location is updated regularly, so it runs on a background thread.
My problem is that when the user closes their tab, I want to stop disable the location services that the app is using with a button click. This button click takes place in a separate Activity from where the map and geolocation service are started. Any help would be greatly appreciated!
PS - I tried to include as much code as possible, so please forgive my clutter.
The map is initiated from the addBtn in this Activity:
public class Alarm extends ActionBarActivity {
public static String TAG = "lstech.aos.debug";
static public boolean geofencesAlreadyRegistered = false;
Button addBtn, lobbyBtn, startTabBtn, settingsBtn;
boolean mapOpen = false;
double latitude, longitude = 0.0;
protected GoogleMap map;
ActionBar actionBar;
Fragment f;
FragmentManager fragmentManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.alarm_layout);
actionBar = getSupportActionBar();
actionBar.hide();
addBtn = (Button) findViewById(R.id.add_geo_button);
startTabBtn = (Button) findViewById(R.id.calculator_button);
lobbyBtn = (Button) findViewById(R.id.lobby_button);
settingsBtn = (Button) findViewById(R.id.settings_button);
TinyDB tinydb = new TinyDB(this);
mapOpen = tinydb.getBoolean("mapOpen");
if (mapOpen)
addBtn.setText(R.string.view_map_button);
else
addBtn.setText(R.string.set_gps_alert);
fragmentManager = getSupportFragmentManager();
f = fragmentManager.findFragmentByTag("uniqueTag");
// SET MAP MARKER AND GEOFENCE
addBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// create a map instance if one doesn't exist
if (f == null) {
fragmentManager
.beginTransaction()
.replace(android.R.id.content, new MapFragment(),
"uniqueTag").commit();
} // keep instance of map if it's already showing
else {
fragmentManager.beginTransaction()
.replace(android.R.id.content, f, "uniqueTag")
.commit();
}
fragmentManager.executePendingTransactions();
startService(new Intent(getApplicationContext(),
GeolocationService.class));
}
});
The GeolocationService class sets up the location and Geofence object:
public class GeolocationService extends Service implements ConnectionCallbacks,
OnConnectionFailedListener, LocationListener, ResultCallback<Status> {
// TinyDB saved value handles: (boolean)"mapReady"
LocationListener listener;
private static final long GEOFENCE_EXPIRATION_IN_HOURS = 12;
private static final long RADIUS = 100;
public static final long GEOFENCE_EXPIRATION_IN_MILLISECONDS = GEOFENCE_EXPIRATION_IN_HOURS
* DateUtils.HOUR_IN_MILLIS;
public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;
public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = UPDATE_INTERVAL_IN_MILLISECONDS / 5;
protected GoogleApiClient mGoogleApiClient;
public static GoogleApiClient mGoogleApiClientStatic;
protected LocationRequest mLocationRequest;
private PendingIntent mPendingIntent;
List<Geofence> mGeofenceList;
static public List<Geofence> mGeofenceListPass;
SimpleGeofence simpleGeo;
static public SimpleGeofence geoFence;
Location mLocation, newLocation;
Intent intent;
public static LocationManager mlocManager;
public static LocationListener mlocListener;
public static android.location.LocationListener mlocListenerProvider;
public static PendingIntent pendingIntent;
public static ConnectionCallbacks connCallbacks;
public static OnConnectionFailedListener connFailedListener;
// ON START
// ***********
#Override
public void onStart(Intent intent, int startId) {
buildGoogleApiClient();
mGoogleApiClient.connect();
mGoogleApiClientStatic = mGoogleApiClient;
mlocManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
mlocListener = this;
mlocListenerProvider = new android.location.LocationListener() {
#Override
public void onLocationChanged(Location arg0) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status,
Bundle extras) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
};
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0L,
0f, mlocListenerProvider);
}
// ON DESTROY
// *************
#Override
public void onDestroy() {
super.onDestroy();
if (mGoogleApiClient.isConnected())
mGoogleApiClient.disconnect();
}
// REGISTER GEOFENCES
// *********************
protected void registerGeofences(Location location) {
if (Alarm.geofencesAlreadyRegistered)
return;
Log.d(Alarm.TAG, "Registering Geofences");
String geoId = "geoId";
simpleGeo = new SimpleGeofence(geoId, location.getLatitude(),
location.getLongitude(), RADIUS,
GEOFENCE_EXPIRATION_IN_MILLISECONDS,
Geofence.GEOFENCE_TRANSITION_ENTER
| Geofence.GEOFENCE_TRANSITION_DWELL
| Geofence.GEOFENCE_TRANSITION_EXIT);
// mGeofenceList.add(new Geofence.Builder()
HashMap<String, SimpleGeofence> geofences = SimpleGeofenceStore
.getInstance().getSimpleGeofences();
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
for (Map.Entry<String, SimpleGeofence> item : geofences.entrySet()) {
SimpleGeofence sg = item.getValue();
sg.setLatitude(simpleGeo.getLatitude());
sg.setLongitude(simpleGeo.getLongitude());
builder.addGeofence(sg.toGeofence());
SimpleGeofenceStore store = SimpleGeofenceStore.getInstance();
store.setLatLong(simpleGeo.getLatitude(), simpleGeo.getLongitude());
// Log.d(Alarm.TAG, sg.getLatitude() + " " + sg.getLongitude());
}
TinyDB tinydb = new TinyDB(getApplicationContext());
tinydb.putBoolean("mapReady", false);
GeofencingRequest geofencingRequest = builder.build();
mPendingIntent = requestPendingIntent();
pendingIntent = mPendingIntent;
LocationServices.GeofencingApi.addGeofences(mGoogleApiClient,
geofencingRequest, mPendingIntent).setResultCallback(this);
Alarm.geofencesAlreadyRegistered = true;
} // end registerGeofences()
// REQUEST PENDING INTENT
// *************************
private PendingIntent requestPendingIntent() {
if (null != mPendingIntent)
return mPendingIntent;
Intent intent = new Intent(this, GeofenceReceiver.class);
return PendingIntent.getService(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
} // end requestPendingIntent()
// START LOCATION UPDATES
// *************************
protected void startLocationUpdates() {
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
} // end startLocationUpdates()
// STOP LOCATION UPDATES
// ************************
protected void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
} // end stopLocationUpdates()
// ON CONNECTED
// ***************
#Override
public void onConnected(Bundle connectionHint) {
Log.i(Alarm.TAG, "Connected to GoogleApiClient");
startLocationUpdates();
} // end onConnected(Bundle connectionHint)
// ON LOCATION CHANGED
// **********************
#Override
public void onLocationChanged(Location location) {
Log.d(Alarm.TAG, "new location : " + location.getLatitude() + ", "
+ location.getLongitude() + ". " + location.getAccuracy());
broadcastLocationFound(location);
if (!Alarm.geofencesAlreadyRegistered)
registerGeofences(location);
} // end onLocationChanged(Location location)
// ON CONNECTION SUSPENDED
// **************************
#Override
public void onConnectionSuspended(int cause) {
Log.i(Alarm.TAG, "Connection suspended");
mGoogleApiClient.connect();
} // end onConnectionSuspended(int cause)
// ON CONNECTION FAILED
// ***********************
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(Alarm.TAG,
"Connection failed: ConnectionResult.getErrorCode() = "
+ result.getErrorCode());
} // end onConnectionFailed(ConnectionResult result)
// BUILD GOOGLE API CLIENT
// **************************
protected synchronized void buildGoogleApiClient() {
Log.i(Alarm.TAG, "Building GoogleApiClient");
mlocListener = this;
connCallbacks = this;
connFailedListener = this;
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
createLocationRequest();
} // end buildGoogleApiClient()
// CREATE LOCATION REQUEST
// **************************
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest
.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
} // end createLocationRequest()
// ON BIND
// **********
#Override
public IBinder onBind(Intent intent) {
return null;
}
// BROADCAST LOCATION FOUND
// ***************************
public void broadcastLocationFound(Location location) {
Intent intent = new Intent(
"com.diligencedojo.tabsitter.geolocation.service");
intent.putExtra("latitude", location.getLatitude());
intent.putExtra("longitude", location.getLongitude());
intent.putExtra("done", 1);
// //
sendBroadcast(intent);
} // end broadcastLocationFound(Location location)
// ON RESULT
// ************
public void onResult(Status status) {
if (status.isSuccess()) {
Toast.makeText(getApplicationContext(),
getString(R.string.geofences_added), Toast.LENGTH_SHORT)
.show();
TinyDB tinydb = new TinyDB(getApplicationContext());
tinydb.putBoolean("mapReady", true);
} else {
Alarm.geofencesAlreadyRegistered = false;
String errorMessage = getErrorString(this, status.getStatusCode());
Toast.makeText(getApplicationContext(), errorMessage,
Toast.LENGTH_SHORT).show();
}
} // end onResult(Status status)
// GET ERROR STRING
// *******************
public static String getErrorString(Context context, int errorCode) {
Resources mResources = context.getResources();
switch (errorCode) {
case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
return mResources.getString(R.string.geofence_not_available);
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
return mResources.getString(R.string.geofence_too_many_geofences);
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
return mResources
.getString(R.string.geofence_too_many_pending_intents);
default:
return mResources.getString(R.string.unknown_geofence_error);
} // end switch (errorCode)
} // end getErrorString(Context context, int errorCode)
} // end GeolocationService Class
The MapFragment is where the actual map, marker, and geofence are displayed:
public class MapFragment extends Fragment {
protected SupportMapFragment mapFragment;
protected GoogleMap map;
protected Marker myPositionMarker;
Double latitude, longitude = 0.0;
Integer transition = 0;
float radius = 0;
long expiration = 0;
Handler handler;
HashMap<String, SimpleGeofence> geofences;
Button lobbyBtn, startTabBtn, settingsBtn;
private Bundle savedState = null;
Context mContext;
boolean mapOpen = false;
public static BroadcastReceiver mReceiver;
public static FragmentActivity fAct;
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
int resultCode = bundle.getInt("done");
if (resultCode == 1) {
latitude = bundle.getDouble("latitude");
longitude = bundle.getDouble("longitude");
updateMarker(latitude, longitude, context);
} // end if (resultCode == 1)
} // end if (bundle != null)
} // end onReceive(Context context, Intent intent)
}; // end BroadcastReceiver receiver = new BroadcastReceiver()
#Override
public void onCreate(Bundle savedInstanceState) {
setRetainInstance(true);
setHasOptionsMenu(true);
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_map, container,
false);
mapFragment = SupportMapFragment.newInstance();
FragmentTransaction fragmentTransaction = getChildFragmentManager()
.beginTransaction();
fragmentTransaction.add(R.id.map_container, mapFragment);
fragmentTransaction.commit();
startTabBtn = (Button) rootView.findViewById(R.id.calculator_button);
lobbyBtn = (Button) rootView.findViewById(R.id.lobby_button);
settingsBtn = (Button) rootView.findViewById(R.id.settings_button);
lobbyBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent toLobby = new Intent(v.getContext(), Lobby.class);
startActivity(toLobby);
}
});
startTabBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent toCalc = new Intent(v.getContext(), CurrentTab.class);
startActivity(toCalc);
}
});
settingsBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent toCalc = new Intent(v.getContext(), StartTab.class);
startActivity(toCalc);
}
});
return rootView;
} // end onCreateView
// ON PAUSE
// ***********
#Override
public void onPause() {
super.onPause();
fAct = getActivity();
getActivity().unregisterReceiver(receiver);
}
// ON RESUME
// ************
#Override
public void onResume() {
super.onResume();
if (mapFragment != null) {
if (map != null)
map.animateCamera(CameraUpdateFactory.zoomTo(15));
mapFragment.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
map = googleMap;
map.animateCamera(CameraUpdateFactory.zoomTo(15));
} // end onMapReady(GoogleMap googleMap)
}); // end mapFragment.getMapAsync(new OnMapReadyCallback()
} // end if (mapFragment != null)
mReceiver = receiver;
getActivity().registerReceiver(
receiver,
new IntentFilter(
"com.diligencedojo.tabsitter.geolocation.service"));
} // end onResume()
// DISPLAY GEOFENCE
// *******************
protected void displayGeofences() {
geofences = SimpleGeofenceStore.getInstance().getSimpleGeofences();
// set circle around marker
for (Map.Entry<String, SimpleGeofence> item : geofences.entrySet()) {
SimpleGeofence sg = item.getValue();
CircleOptions circleOptions1 = new CircleOptions()
.center(new LatLng(sg.getLatitude(), sg.getLongitude()))
.radius(sg.getRadius()).strokeColor(Color.BLACK)
.strokeWidth(2).fillColor(0x500000ff);
map.addCircle(circleOptions1);
}
} // end displayGeofences()
// CREATE MARKER
// ****************
protected void createMarker(Double latitude, Double longitude,
Context context) {
LatLng latLng = new LatLng(latitude, longitude);
myPositionMarker = map.addMarker(new MarkerOptions().position(latLng));
map.moveCamera(CameraUpdateFactory.newLatLng(latLng));
// display the geofence after the marker is placed to ensure that the
// map is being displayed successfully
displayGeofences();
// save the state of the map (if it's open or not)
TinyDB tinydb = new TinyDB(context);
tinydb.putBoolean("mapOpen", true);
tinydb.putDouble("latitude", latitude);
tinydb.putDouble("longitude", longitude);
}
// UPDATE MARKER
// ****************
protected void updateMarker(Double latitude, Double longitude,
Context context) {
if (myPositionMarker == null)
createMarker(latitude, longitude, context);
LatLng latLng = new LatLng(latitude, longitude);
myPositionMarker.setPosition(latLng);
map.moveCamera(CameraUpdateFactory.newLatLng(latLng));
}
// ON CREATE OPTIONS MENU
// *************************
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_map, menu);
}
// ON OPTIONS SELECTED
// **********************
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
} // end MapFragment Class
The CloseTab Activity is where I want to stop any GPS service that the app is using. I have tried a lot of different approaches, so bear with my code.
public class CloseTab extends Activity {
Button numDrinksBtn, estBillBtn, avgCostBtn, tipAmtBtn, totBillBtn,
dismissBtn;
TextView tipExpl;
int currDrinkTotal = 0;
double currTabTotal, currTipTotal, tipAmt = 0.0;
boolean isSobriety, isSaver, isCount = false;
GoogleApiClient mGoogleApiClient;
SimpleGeofence sg;
LocationListener mlocListener;
LocationManager locationManager;
android.location.LocationListener mlocListenerProvider;
PendingIntent mPendingIntent;
ConnectionCallbacks mConnCallbacks;
OnConnectionFailedListener mConnFailedListener;
BroadcastReceiver mReceiver;
FragmentActivity fAct;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.close_tab_layout);
numDrinksBtn = (Button) findViewById(R.id.num_drinks_amout);
estBillBtn = (Button) findViewById(R.id.est_bill_amout);
avgCostBtn = (Button) findViewById(R.id.avg_cost_amout);
tipExpl = (TextView) findViewById(R.id.tip_expl_text);
tipAmtBtn = (Button) findViewById(R.id.total_tip_amount);
totBillBtn = (Button) findViewById(R.id.total_bill_amout);
dismissBtn = (Button) findViewById(R.id.dismiss_button);
getSavedValues(); // populate view with saved values
// DISMISS BUTTON
dismissBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mGoogleApiClient = GeolocationService.mGoogleApiClientStatic;
if (mGoogleApiClient.isConnected()) {
mlocListener = GeolocationService.mlocListener;
locationManager = GeolocationService.mlocManager;
mlocListenerProvider = GeolocationService.mlocListenerProvider;
mPendingIntent = GeolocationService.pendingIntent;
mConnCallbacks = GeolocationService.connCallbacks;
mConnFailedListener = GeolocationService.connFailedListener;
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, mlocListener);
LocationServices.GeofencingApi.removeGeofences(
mGoogleApiClient, mPendingIntent);
locationManager.removeUpdates(mlocListenerProvider);
mGoogleApiClient
.unregisterConnectionCallbacks(mConnCallbacks);
mGoogleApiClient
.unregisterConnectionFailedListener(mConnFailedListener);
// mGoogleApiClient.stopAutoManage(f);
// mReceiver.abortBroadcast();
// fAct = MapFragment.fAct;
// mGoogleApiClient.stopAutoManage(fAct);
// mReceiver = MapFragment.mReceiver;
// fAct.unregisterReceiver(mReceiver);
mGoogleApiClient.disconnect();
}
turnGPSOff();
Intent intent = new Intent(
"android.location.GPS_ENABLED_CHANGE");
intent.putExtra("enabled", false);
sendBroadcast(intent);
ActivityManager am = (ActivityManager) getSystemService(Activity.ACTIVITY_SERVICE);
am.killBackgroundProcesses("com.diligencedojo.tabsitter");
am.getRunningServices(100).clear();
am.getRunningAppProcesses().clear();
// clear all saved values
TinyDB tinydb = new TinyDB(getApplicationContext());
tinydb.clear();
finish();
startActivity(getIntent());
Intent toLobby = new Intent(v.getContext(), Lobby.class);
startActivity(toLobby);
}
});
} // end onCreate
// automatic turn off the gps
public void turnGPSOff() {
Context ctx = getApplicationContext();
// CloseTab.this
String provider = Settings.Secure.getString(ctx.getContentResolver(),
Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
if (provider.contains("gps")) { // if gps is enabled
// Toast.makeText(getApplicationContext(),
// "in->provider.contains(gps)", Toast.LENGTH_SHORT).show();
final Intent poke = new Intent();
poke.setClassName("com.android.settings",
"com.android.settings.widget.SettingsAppWidgetProvider");
poke.addCategory(Intent.CATEGORY_ALTERNATIVE);
poke.setData(Uri.parse("3"));
ctx.sendBroadcast(poke);
// CloseTab.this.sendBroadcast(poke);
}
}
..........
These are the classes I am using for my geofence:
SimpleGeofence Class
public class SimpleGeofence {
private final String id;
private double latitude;
private double longitude;
private final float radius;
private long expirationDuration;
private int transitionType;
private int loiteringDelay = 60000;
public SimpleGeofence(String geofenceId, double latitude, double longitude,
float radius, long expiration, int transition) {
this.id = geofenceId;
this.latitude = latitude;
this.longitude = longitude;
this.radius = radius;
this.expirationDuration = expiration;
this.transitionType = transition;
}
public String getId() {
return id;
}
public void setLatitude(Double mLat) {
this.latitude = mLat;
}
public double getLatitude() {
return latitude;
}
public void setLongitude(Double mLong) {
this.longitude = mLong;
}
public double getLongitude() {
return longitude;
}
public float getRadius() {
return radius;
}
public void setExpirationDuration(long mExpirationDuration) {
this.expirationDuration = mExpirationDuration;
}
public long getExpirationDuration() {
return expirationDuration;
}
public int getTransitionType() {
return transitionType;
}
public Geofence toGeofence() {
Geofence g = new Geofence.Builder().setRequestId(getId())
.setTransitionTypes(transitionType)
.setCircularRegion(getLatitude(), getLongitude(), getRadius())
.setExpirationDuration(expirationDuration)
.setLoiteringDelay(loiteringDelay).build();
return g;
}
} // end SimpleGefence Class
SimpleGeofenceStore Class
public class SimpleGeofenceStore {
private static final long GEOFENCE_EXPIRATION_IN_HOURS = 12;
private static final long RADIUS = 100;
public static final long GEOFENCE_EXPIRATION_IN_MILLISECONDS = GEOFENCE_EXPIRATION_IN_HOURS
* DateUtils.HOUR_IN_MILLIS;
protected HashMap<String, SimpleGeofence> geofences = new HashMap<String, SimpleGeofence>();
private static SimpleGeofenceStore instance = new SimpleGeofenceStore();
private double latitude;
private double longitude;
public static SimpleGeofenceStore getInstance() {
// mContext = context;
return instance;
}
public void setLatLong(Double mLat, Double mLong) {
this.latitude = mLat;
this.longitude = mLong;
}
public Double getLatitude() {
return latitude;
}
public Double getLongitude() {
return longitude;
}
private SimpleGeofenceStore() {
geofences.put("My House", new SimpleGeofence("My House", getLatitude(),
getLongitude(), RADIUS, GEOFENCE_EXPIRATION_IN_MILLISECONDS,
Geofence.GEOFENCE_TRANSITION_ENTER
| Geofence.GEOFENCE_TRANSITION_DWELL
| Geofence.GEOFENCE_TRANSITION_EXIT));
}
public HashMap<String, SimpleGeofence> getSimpleGeofences() {
return this.geofences;
}
} // end SimpleGeofenceStore Class
To disable the location services and processes on a button click from a different Activity, I followed these steps. First I defined the location variables in GeolocationServices.java as public and static. This allows you access to them in the other Activities. Next, I put a boolean variable "tabClosed" around everything that could potentially reconnect the GoogleApiClient after it had been disconnected. I'm not entirely sure that I needed this.
GeolocationServices.java
public class GeolocationService extends Service implements ConnectionCallbacks,
OnConnectionFailedListener, LocationListener, ResultCallback<Status> {
// TinyDB saved value handles: (boolean)"mapReady"
LocationListener listener;
private static final long GEOFENCE_EXPIRATION_IN_HOURS = 12;
private static final long RADIUS = 100;
public static final long GEOFENCE_EXPIRATION_IN_MILLISECONDS = GEOFENCE_EXPIRATION_IN_HOURS
* DateUtils.HOUR_IN_MILLIS;
public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;
public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS = UPDATE_INTERVAL_IN_MILLISECONDS / 5;
// protected GoogleApiClient mGoogleApiClient;
public static GoogleApiClient mGoogleApiClient;
protected LocationRequest mLocationRequest;
// private PendingIntent mPendingIntent;
public static PendingIntent mPendingIntent;
List<Geofence> mGeofenceList;
SimpleGeofence simpleGeo;
Location mLocation, newLocation;
public static LocationManager mlocManager;
public static LocationListener mlocListener;
public static ConnectionCallbacks connCallbacks;
public static OnConnectionFailedListener connFailedListener;
public static ResultCallback<Status> mGeoCallback;
// ON START
// ***********
#Override
public void onStart(Intent intent, int startId) {
TinyDB tinydb = new TinyDB(getApplicationContext());
boolean tabClosed = tinydb.getBoolean("tabClosed");
if (!tabClosed) {
buildGoogleApiClient();
mGoogleApiClient.connect();
}
}
// ON DESTROY
// *************
#Override
public void onDestroy() {
// super.onDestroy();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
mlocManager.removeUpdates(mPendingIntent);
mlocManager.removeProximityAlert(mPendingIntent);
mPendingIntent.cancel();
}
super.onDestroy();
}
// REGISTER GEOFENCES
// *********************
protected void registerGeofences(Location location) {
if (Alarm.geofencesAlreadyRegistered)
return;
Log.d(Alarm.TAG, "Registering Geofences");
String geoId = "geoId";
simpleGeo = new SimpleGeofence(geoId, location.getLatitude(),
location.getLongitude(), RADIUS,
GEOFENCE_EXPIRATION_IN_MILLISECONDS,
Geofence.GEOFENCE_TRANSITION_ENTER
| Geofence.GEOFENCE_TRANSITION_DWELL
| Geofence.GEOFENCE_TRANSITION_EXIT);
// //
HashMap<String, SimpleGeofence> geofences = SimpleGeofenceStore
.getInstance().getSimpleGeofences();
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
for (Map.Entry<String, SimpleGeofence> item : geofences.entrySet()) {
SimpleGeofence sg = item.getValue();
sg.setLatitude(simpleGeo.getLatitude());
sg.setLongitude(simpleGeo.getLongitude());
builder.addGeofence(sg.toGeofence());
SimpleGeofenceStore store = SimpleGeofenceStore.getInstance();
store.setLatLong(simpleGeo.getLatitude(), simpleGeo.getLongitude());
// Log.d(Alarm.TAG, sg.getLatitude() + " " + sg.getLongitude());
}
TinyDB tinydb = new TinyDB(getApplicationContext());
tinydb.putBoolean("mapReady", false);
GeofencingRequest geofencingRequest = builder.build();
mPendingIntent = requestPendingIntent();
mGeoCallback = this;
LocationServices.GeofencingApi.addGeofences(mGoogleApiClient,
geofencingRequest, mPendingIntent).setResultCallback(
mGeoCallback);
Alarm.geofencesAlreadyRegistered = true;
} // end registerGeofences()
// REQUEST PENDING INTENT
// *************************
private PendingIntent requestPendingIntent() {
PendingIntent tempPendingIntent = null;
if (null != mPendingIntent)
return mPendingIntent;
TinyDB tinydb = new TinyDB(getApplicationContext());
boolean tabClosed = tinydb.getBoolean("tabClosed");
if (!tabClosed) {
Intent intent = new Intent(this, GeofenceReceiver.class);
tempPendingIntent = PendingIntent.getService(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
return tempPendingIntent;
} // end requestPendingIntent()
// BROADCAST LOCATION FOUND
// ***************************
public void broadcastLocationFound(Location location) {
Intent intent = new Intent(
"com.diligencedojo.tabsitter.geolocation.service");
intent.putExtra("latitude", location.getLatitude());
intent.putExtra("longitude", location.getLongitude());
intent.putExtra("done", 1);
TinyDB tinydb = new TinyDB(getApplicationContext());
boolean tabClosed = tinydb.getBoolean("tabClosed");
if (!tabClosed)
sendBroadcast(intent);
} // end broadcastLocationFound(Location location)
// START LOCATION UPDATES
// *************************
protected void startLocationUpdates() {
TinyDB tinydb = new TinyDB(getApplicationContext());
boolean tabClosed = tinydb.getBoolean("tabClosed");
if (!tabClosed) { //
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
}
} // end startLocationUpdates()
// STOP LOCATION UPDATES
// ************************
protected void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
} // end stopLocationUpdates()
// ON CONNECTED
// ***************
#Override
public void onConnected(Bundle connectionHint) {
Log.i(Alarm.TAG, "Connected to GoogleApiClient");
startLocationUpdates();
} // end onConnected(Bundle connectionHint)
// ON LOCATION CHANGED
// **********************
#Override
public void onLocationChanged(Location location) {
Log.d(Alarm.TAG, "new location : " + location.getLatitude() + ", "
+ location.getLongitude() + ". " + location.getAccuracy());
TinyDB tinydb = new TinyDB(getApplicationContext());
boolean tabClosed = tinydb.getBoolean("tabClosed");
if (!tabClosed)
broadcastLocationFound(location);
if (!Alarm.geofencesAlreadyRegistered)
registerGeofences(location);
} // end onLocationChanged(Location location)
// ON CONNECTION SUSPENDED
// **************************
#Override
public void onConnectionSuspended(int cause) {
Log.i(Alarm.TAG, "Connection suspended");
TinyDB tinydb = new TinyDB(getApplicationContext());
boolean tabClosed = tinydb.getBoolean("tabClosed");
if (!tabClosed)
mGoogleApiClient.connect();
} // end onConnectionSuspended(int cause)
// ON CONNECTION FAILED
// ***********************
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.i(Alarm.TAG,
"Connection failed: ConnectionResult.getErrorCode() = "
+ result.getErrorCode());
} // end onConnectionFailed(ConnectionResult result)
// BUILD GOOGLE API CLIENT
// **************************
protected synchronized void buildGoogleApiClient() {
Log.i(Alarm.TAG, "Building GoogleApiClient");
TinyDB tinydb = new TinyDB(getApplicationContext());
boolean tabClosed = tinydb.getBoolean("tabClosed");
if (!tabClosed) {
mlocListener = this;
connCallbacks = this;
connFailedListener = this;
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(connCallbacks)
.addOnConnectionFailedListener(connFailedListener)
.addApi(LocationServices.API).build();
createLocationRequest();
}
} // end buildGoogleApiClient()
// CREATE LOCATION REQUEST
// **************************
protected void createLocationRequest() {
TinyDB tinydb = new TinyDB(getApplicationContext());
boolean tabClosed = tinydb.getBoolean("tabClosed");
if (!tabClosed) {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest
.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
} // end createLocationRequest()
// ON BIND
// **********
#Override
public IBinder onBind(Intent intent) {
return null;
}
// ON RESULT
// ************
public void onResult(Status status) {
TinyDB tinydb = new TinyDB(getApplicationContext());
boolean tabClosed = tinydb.getBoolean("tabClosed");
if (!tabClosed) {
if (status.isSuccess()) {
Toast.makeText(getApplicationContext(),
getString(R.string.geofences_added), Toast.LENGTH_SHORT)
.show();
tinydb.putBoolean("mapReady", true);
} else {
Alarm.geofencesAlreadyRegistered = false;
String errorMessage = getErrorString(this,
status.getStatusCode());
Toast.makeText(getApplicationContext(), errorMessage,
Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getApplicationContext(),
"Tab closed, do not add geofence.", Toast.LENGTH_SHORT)
.show();
}
} // end onResult(Status status)
// GET ERROR STRING
// *******************
public static String getErrorString(Context context, int errorCode) {
Resources mResources = context.getResources();
switch (errorCode) {
case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
return mResources.getString(R.string.geofence_not_available);
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
return mResources.getString(R.string.geofence_too_many_geofences);
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
return mResources
.getString(R.string.geofence_too_many_pending_intents);
default:
return mResources.getString(R.string.unknown_geofence_error);
} // end switch (errorCode)
} // end getErrorString(Context context, int errorCode)
} // end GeolocationService Class
Now in CloseTab.java, I retrieved the variables I had declared public static in GeolocationService.java. It is important to use the same pending intent as a parameter when disabling the location services. First I removed the geofence, then the location updates, and then I disconnected the google api client all together. Finally, I used stopService(intent) to remove any lingering services (such as those started within my MapFragment.java).
public class CloseTab extends Activity {
Button numDrinksBtn, estBillBtn, avgCostBtn, tipAmtBtn, totBillBtn,
dismissBtn;
TextView tipExpl;
int currDrinkTotal = 0;
double currTabTotal, currTipTotal, tipAmt = 0.0;
boolean isSobriety, isSaver, isCount = false;
GoogleApiClient mGoogleApiClient;
PendingIntent mPendingIntent;
ResultCallback<Status> mGeoCallback;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.close_tab_layout);
numDrinksBtn = (Button) findViewById(R.id.num_drinks_amout);
estBillBtn = (Button) findViewById(R.id.est_bill_amout);
avgCostBtn = (Button) findViewById(R.id.avg_cost_amout);
tipExpl = (TextView) findViewById(R.id.tip_expl_text);
tipAmtBtn = (Button) findViewById(R.id.total_tip_amount);
totBillBtn = (Button) findViewById(R.id.total_bill_amout);
dismissBtn = (Button) findViewById(R.id.dismiss_button);
getSavedValues(); // populate view with saved values
// DISMISS BUTTON
dismissBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mGoogleApiClient = GeolocationService.mGoogleApiClient;
if (mGoogleApiClient.isConnected()) {
// Log.d("DBG", "mGoogleApiClient.isConnected()");
mPendingIntent = GeolocationService.mPendingIntent;
mGeoCallback = GeolocationService.mGeoCallback;
try { // Log.d("DBG", "try hit in CloseTab");
// use the same pending intent set in GeolocationService
// to identify the right things to disable
// Remove geofence
LocationServices.GeofencingApi.removeGeofences(
mGoogleApiClient, mPendingIntent)
.setResultCallback(mGeoCallback);
// Remove location updates
LocationServices.FusedLocationApi
.removeLocationUpdates(mGoogleApiClient,
mPendingIntent);
// Disconnect google client
mGoogleApiClient.disconnect();
// Remove any lingering services
Intent intent = new Intent(getApplicationContext(),
GeolocationService.class);
stopService(intent);
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use
// ACCESS_FINE_LOCATION permission.
Log.d("DBG", "catch hit in CloseTab");
}
}
// clear all saved values
TinyDB tinydb = new TinyDB(getApplicationContext());
tinydb.clear();
// tab has been closed. this is used as a condition to determine
// if gps should be allowed to reconnect on it's own
tinydb.putBoolean("tabClosed", true);
Intent toLobby = new Intent(v.getContext(), Lobby.class);
startActivity(toLobby);
}
});
}// end onCreate
Hopefully this will help someone else.