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.
Related
My app is about getting location in background service. However, it cannot return latitude and longitude. Here is the code.
Service side:
public class Map extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private static final String TAG = Map.class.getSimpleName();
GoogleApiClient mLocationClient;
LocationRequest mLocationRequest = new LocationRequest();
public static final String ACTION_LOCATION_BROADCAST = Map.class.getName() + "LocationBroadcast";
public static final String EXTRA_LATITUDE = "extra_latitude";
public static final String EXTRA_LONGITUDE = "extra_longitude";
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mLocationClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(5000);
int priority = LocationRequest.PRIORITY_HIGH_ACCURACY;
mLocationRequest.setPriority(priority);
mLocationClient.connect();
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onConnected(Bundle dataBundle) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "== Error On onConnected() Permission not granted");
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mLocationClient, mLocationRequest, this);
Log.d(TAG, "Connected to Google API");
}
#Override
public void onConnectionSuspended(int i) {
Log.d(TAG, "Connection suspended");
}
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, "Location changed");
if (location != null) {
Log.d(TAG, "== location != null");
sendMessageToUI(String.valueOf(location.getLatitude()), String.valueOf(location.getLongitude()));
}
}
private void sendMessageToUI(String lat, String lng) {
Log.d(TAG, "Sending info...");
Intent intent = new Intent(ACTION_LOCATION_BROADCAST);
intent.putExtra(EXTRA_LATITUDE, lat);
intent.putExtra(EXTRA_LONGITUDE, lng);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.d(TAG, "Failed to connect to Google API");
}
}
MainActivity side:
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
private boolean mAlreadyStartedService = false;
private FirebaseUser user;
private FirebaseAuth mAuth;
private DatabaseReference mDatabase;
private double longitude;
private double latitude;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAuth = FirebaseAuth.getInstance();
mDatabase = FirebaseDatabase.getInstance().getReference();
user = mAuth.getCurrentUser();
LocalBroadcastManager.getInstance(this).registerReceiver(
bReceiver, new IntentFilter("ACTION_LOCATION_BROADCAST"));
}
private BroadcastReceiver bReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String latitude = intent.getStringExtra(Map.EXTRA_LATITUDE);
String longitude = intent.getStringExtra(Map.EXTRA_LONGITUDE);
dd.setText("HI");
if (latitude != null && longitude != null) {
mAuth = FirebaseAuth.getInstance();
user = mAuth.getCurrentUser();
if (!String.valueOf(latitude).equals(""))
mDatabase.child("users").child(user.getUid()).child("latitude").setValue(latitude);
if (!String.valueOf(longitude).equals(""))
mDatabase.child("users").child(user.getUid()).child("longitude").setValue(longitude);
cc.setText("Latitude:" + latitude + " Longitude: " + longitude);
}
}
};
private void startStep3() {
Intent intent = new Intent(this, Map.class);
this.startService(intent);
ff.setText("3ok");
mAlreadyStartedService = true;
}
#Override
public void onResume() {
super.onResume();
startStep3();
ee.setText("Start");
}
#Override
public void onDestroy() {
stopService(new Intent(this, Map.class));
mAlreadyStartedService = false;
super.onDestroy();
}
}
AndroidManifest:
<service android:name=".Map" />
It can show "start" and "3ok" on the page but cannot get the location. It appears "TextView" instead of the location information. Did I miss any codes and where is the problem? Is it a correct way to use service?Thank you.
I am really stuck at this point.Geofence really works fine when app is in forground that is notification comes properly. but when app goes is in background notification not comes.
I want like this when app is in background my geofence never expired and and get notified if user is outside the fence.
Also attached the code below:-
public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener,
ResultCallback<Status> {
protected static final int REQUEST_CHECK_SETTINGS = 0x1;
GoogleApiClient googleApiClient;
private MapFragment mapFragment;
private static final String TAG = MainActivity.class.getSimpleName();
private GoogleMap map;
private Location lastLocation;
private static final String NOTIFICATION_MSG = "NOTIFICATION MSG";
SharedPreferences pref;
SharedPreferences.Editor editor;
public static Intent makeNotificationIntent(Context context, String msg) {
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra(NOTIFICATION_MSG, msg);
return intent;
}
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_geofence);
pref = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
editor = pref.edit();
initGMaps();
createGoogleApi();
}
private void initGMaps() {
//mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
//mapFragment.getMapAsync(this);
}
private void createGoogleApi() {
Log.d(TAG, "createGoogleApi()");
if (googleApiClient == null) {
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
#Override
protected void onStart() {
super.onStart();
googleApiClient.connect();
settingsrequest();
}
public void settingsrequest() {
LocationRequest locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(30 * 1000);
locationRequest.setFastestInterval(5 * 1000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest);
builder.setAlwaysShow(true); //this is the key ingredient
PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(googleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
final LocationSettingsStates state = result.getLocationSettingsStates();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
// All location settings are satisfied. The client can initialize location
// requests here.
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied. But could be fixed by showing the user
// a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(MainActivity.this, REQUEST_CHECK_SETTINGS);
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are not satisfied. However, we have no way to fix the
// settings so we won't show the dialog.
break;
}
}
});
}
#Override
protected void onStop() {
super.onStop();
// Disconnect GoogleApiClient when stopping Activity
googleApiClient.disconnect();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
// Check for the integer request code originally supplied to startResolutionForResult().
case REQUEST_CHECK_SETTINGS:
switch (resultCode) {
case Activity.RESULT_OK:
startLocationUpdates();
break;
case Activity.RESULT_CANCELED:
settingsrequest();//keep asking if imp or do whatever
break;
}
break;
}
}
#Override
public void onConnected(#Nullable Bundle bundle) {
// googleApiClient.disconnect();
Log.i(TAG, "onConnected()");
getLastKnownLocation();
//recoverGeofenceMarker();
startGeofence();
}
private final int REQ_PERMISSION = 999;
// Check for permission to access Location
private boolean checkPermission() {
Log.d(TAG, "checkPermission()");
// Ask for permission if it wasn't granted yet
return (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED);
}
// Asks for permission
private void askPermission() {
Log.d(TAG, "askPermission()");
ActivityCompat.requestPermissions(
this,
new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
REQ_PERMISSION
);
}
private void getLastKnownLocation() {
Log.d(TAG, "getLastKnownLocation()");
if (checkPermission()) {
lastLocation = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
if (lastLocation != null) {
Log.i(TAG, "LasKnown location. " +
"Long: " + lastLocation.getLongitude() +
" | Lat: " + lastLocation.getLatitude());
writeLastLocation();
startLocationUpdates();
} else {
Log.w(TAG, "No location retrieved yet");
startLocationUpdates();
}
} else askPermission();
}
private void writeActualLocation(Location location) {
//textLat.setText("Lat: " + location.getLatitude());
//textLong.setText("Long: " + location.getLongitude());
markerLocation(new LatLng(location.getLatitude(), location.getLongitude()));
}
private void writeLastLocation() {
writeActualLocation(lastLocation);
}
private Marker locationMarker;
private void markerLocation(LatLng latLng) {
Log.i(TAG, "markerLocation(" + latLng + ")");
String title = latLng.latitude + ", " + latLng.longitude;
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.title(title);
if (map != null) {
if (locationMarker != null)
locationMarker.remove();
locationMarker = map.addMarker(markerOptions);
float zoom = 14f;
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, zoom);
map.animateCamera(cameraUpdate);
}
}
// Start Geofence creation process
private void startGeofence() {
Log.i(TAG, "startGeofence()");
Geofence geofence = createGeofence();
GeofencingRequest geofenceRequest = createGeofenceRequest(geofence);
addGeofence(geofenceRequest);
}
private static final long GEO_DURATION = 60 * 60 * 1000;
private static final String GEOFENCE_REQ_ID = "My Geofence";
private static final float GEOFENCE_RADIUS = 500.0f; // in meters
// Create a Geofence
private Geofence createGeofence() {
Log.d(TAG, "createGeofence");
//Intent i = getIntent();
//double la = i.getDoubleExtra("latitude", 0);
//double lo = i.getDoubleExtra("longitude", 0);
return new Geofence.Builder()
.setRequestId(GEOFENCE_REQ_ID)
.setCircularRegion(18.457532, 73.867746, GEOFENCE_RADIUS)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_EXIT)
.build();
}
// Create a Geofence Request
private GeofencingRequest createGeofenceRequest(Geofence geofence) {
Log.d(TAG, "createGeofenceRequest");
return new GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_EXIT)
.addGeofence(geofence)
.build();
}
private PendingIntent geoFencePendingIntent;
private static final int GEOFENCE_REQ_CODE = 0;
private PendingIntent createGeofencePendingIntent() {
Log.d(TAG, "createGeofencePendingIntent");
if (geoFencePendingIntent != null)
return geoFencePendingIntent;
Intent intent = new Intent("com.aol.android.geofence.ACTION_RECEIVE_GEOFENCE");
return PendingIntent.getBroadcast(
this, GEOFENCE_REQ_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
// Add the created GeofenceRequest to the device's monitoring list
private void addGeofence(GeofencingRequest request) {
Log.d(TAG, "addGeofence");
if (checkPermission())
LocationServices.GeofencingApi.addGeofences(
googleApiClient,
request,
createGeofencePendingIntent()
).setResultCallback(this);
}
#Override
public void onConnectionSuspended(int i) {
Log.w(TAG, "onConnectionSuspended()");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.w(TAG, "onConnectionFailed()");
}
private LocationRequest locationRequest;
// Defined in mili seconds.
// This number in extremely low, and should be used only for debug
private final int UPDATE_INTERVAL = 1000;
private final int FASTEST_INTERVAL = 900;
// Start location Updates
private void startLocationUpdates() {
Log.i(TAG, "startLocationUpdates()");
locationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
if (checkPermission())
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, "onLocationChanged [" + location + "]");
lastLocation = location;
writeActualLocation(location);
}
#Override
public void onResult(#NonNull Status status) {
Log.i(TAG, "onResult: " + status);
if (status.isSuccess()) {
// saveGeofence();
//drawGeofence();
} else {
// inform about fail
}
}
}
also attached Reciever code:-
public class GeofenceReciever extends BroadcastReceiver {
private static final String TAG = "BootReceiver";
Context contextBootReceiver;
Intent intent;
public static final int GEOFENCE_NOTIFICATION_ID = 0;
SharedPreferences pref;
SharedPreferences.Editor editor;
#Override
public void onReceive(Context context, Intent intent) {
this.contextBootReceiver = context;
this.intent = intent;
pref = PreferenceManager.getDefaultSharedPreferences(context);
editor = pref.edit();
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
// Handling errors
if (geofencingEvent.hasError()) {
String errorMsg = getErrorString(geofencingEvent.getErrorCode());
Log.e(TAG, errorMsg);
return;
}
int geoFenceTransition = geofencingEvent.getGeofenceTransition();
// Check if the transition type is of interest
if (geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
// Get the geofence that were triggered
Log.d("Trnsition", "Exited");
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
String geofenceTransitionDetails = getGeofenceTrasitionDetails(geoFenceTransition, triggeringGeofences);
// Send notification details as a String
//if (feedback.equalsIgnoreCase("F;1;")) {
// String temp = feedback;
sendNotification(geofenceTransitionDetails);
}
}
private String getGeofenceTrasitionDetails(int geoFenceTransition, List<Geofence> triggeringGeofences) {
// get the ID of each geofence triggered
ArrayList<String> triggeringGeofencesList = new ArrayList<>();
for (Geofence geofence : triggeringGeofences) {
triggeringGeofencesList.add(geofence.getRequestId());
}
String status = "Some switches are on";
if (geoFenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER)
System.out.println(status);
return status + TextUtils.join(", ", triggeringGeofencesList);
}
private void sendNotification(String msg) {
//intent = new Intent(contextBootReceiver, MainActivity.class);
//intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
//contextBootReceiver.startActivity(intent);
Log.i(TAG, "sendNotification: " + msg);
// Intent to start the main Activity
Intent notificationIntent = MainActivity.makeNotificationIntent(
contextBootReceiver, msg
);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(contextBootReceiver);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(notificationIntent);
PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Creating and sending Notification
NotificationManager notificatioMng =
(NotificationManager) contextBootReceiver.getSystemService(Context.NOTIFICATION_SERVICE);
notificatioMng.notify(
GEOFENCE_NOTIFICATION_ID,
createNotification(msg, notificationPendingIntent));
}
// Create notification
private Notification createNotification(String msg, PendingIntent notificationPendingIntent) {
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(contextBootReceiver);
notificationBuilder
.setSmallIcon(R.drawable.ic_action_location)
.setColor(Color.RED)
.setContentTitle(msg)
.setContentText("Droidhomes Notification!")
.setContentIntent(notificationPendingIntent)
.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)
.setAutoCancel(true);
return notificationBuilder.build();
}
private static String getErrorString(int errorCode) {
switch (errorCode) {
case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
return "GeoFence not available";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
return "Too many GeoFences";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
return "Too many pending intents";
default:
return "Unknown error.";
}
}
}
Write your service like this:
public class GeoFencingService extends Service{
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//write your notification code here
//use START_STICKY if you want your service keep running else use START_NOT_STICKY
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
//use this method to communicate with your activity
return null;
}
}
for detailed explanation have a look at these two links:
https://developer.android.com/guide/components/services.html
http://www.vogella.com/tutorials/AndroidServices/article.html
Let me know if any more help is required
So Far :-
When user in same(under fence area) it gives notification "user enters in area" is ok.But same user leave fence area its not notified.
This is my code:-
public class MainActivity extends AppCompatActivity implements
GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener,
LocationListener, OnMapReadyCallback, GoogleMap.OnMapClickListener, GoogleMap.OnMarkerClickListener,
ResultCallback<Status>
{
private static final String TAG = MainActivity.class.getSimpleName();
private GoogleMap map;
private GoogleApiClient googleApiClient;
private Location lastLocation;
private TextView textLat, textLong;
private MapFragment mapFragment;
private static final String NOTIFICATION_MSG = "NOTIFICATION MSG";
// Create a Intent send by the notification
public static Intent makeNotificationIntent(Context context, String msg) {
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra(NOTIFICATION_MSG, msg);
return intent;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textLat = (TextView) findViewById(R.id.lat);
textLong = (TextView) findViewById(R.id.lon);
// initialize GoogleMaps
initGMaps();
// create GoogleApiClient
createGoogleApi();
}
// Create GoogleApiClient instance
private void createGoogleApi() {
Log.d(TAG, "createGoogleApi()");
if (googleApiClient == null) {
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
}
#Override
protected void onStart() {
super.onStart();
// Call GoogleApiClient connection when starting the Activity
googleApiClient.connect();
}
#Override
protected void onStop() {
super.onStop();
// Disconnect GoogleApiClient when stopping Activity
googleApiClient.disconnect();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.geofence: {
startGeofence();
return true;
}
case R.id.clear: {
clearGeofence();
return true;
}
}
return super.onOptionsItemSelected(item);
}
private final int REQ_PERMISSION = 999;
// Check for permission to access Location
private boolean checkPermission() {
Log.d(TAG, "checkPermission()");
// Ask for permission if it wasn't granted yet
return (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED);
}
// Asks for permission
private void askPermission() {
Log.d(TAG, "askPermission()");
ActivityCompat.requestPermissions(
this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQ_PERMISSION
);
}
// Verify user's response of the permission requested
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
Log.d(TAG, "onRequestPermissionsResult()");
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQ_PERMISSION: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted
getLastKnownLocation();
} else {
// Permission denied
permissionsDenied();
}
break;
}
}
}
// App cannot work without the permissions
private void permissionsDenied() {
Log.w(TAG, "permissionsDenied()");
// TODO close app and warn user
}
// Initialize GoogleMaps
private void initGMaps() {
mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
// Callback called when Map is ready
#Override
public void onMapReady(GoogleMap googleMap) {
Log.d(TAG, "onMapReady()");
map = googleMap;
map.setOnMapClickListener(this);
map.setOnMarkerClickListener(this);
}
#Override
public void onMapClick(LatLng latLng) {
Log.d(TAG, "onMapClick(" + latLng + ")");
//markerForGeofence(latLng);
}
#Override
public boolean onMarkerClick(Marker marker) {
Log.d(TAG, "onMarkerClickListener: " + marker.getPosition());
return false;
}
private LocationRequest locationRequest;
// Defined in mili seconds.
// This number in extremely low, and should be used only for debug
private final int UPDATE_INTERVAL = 1000;
private final int FASTEST_INTERVAL = 900;
// Start location Updates
private void startLocationUpdates() {
Log.i(TAG, "startLocationUpdates()");
locationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(UPDATE_INTERVAL)
.setFastestInterval(FASTEST_INTERVAL);
if (checkPermission())
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, "onLocationChanged [" + location + "]");
lastLocation = location;
writeActualLocation(location);
}
// GoogleApiClient.ConnectionCallbacks connected
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.i(TAG, "onConnected()");
getLastKnownLocation();
recoverGeofenceMarker();
startGeofence();
}
// GoogleApiClient.ConnectionCallbacks suspended
#Override
public void onConnectionSuspended(int i) {
Log.w(TAG, "onConnectionSuspended()");
}
// GoogleApiClient.OnConnectionFailedListener fail
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.w(TAG, "onConnectionFailed()");
}
// Get last known location
private void getLastKnownLocation() {
Log.d(TAG, "getLastKnownLocation()");
if (checkPermission()) {
lastLocation = LocationServices.FusedLocationApi.getLastLocation(googleApiClient);
if (lastLocation != null) {
Log.i(TAG, "LasKnown location. " +
"Long: " + lastLocation.getLongitude() +
" | Lat: " + lastLocation.getLatitude());
writeLastLocation();
startLocationUpdates();
} else {
Log.w(TAG, "No location retrieved yet");
startLocationUpdates();
}
} else askPermission();
}
private void writeActualLocation(Location location) {
textLat.setText("Lat: " + location.getLatitude());
textLong.setText("Long: " + location.getLongitude());
markerLocation(new LatLng(location.getLatitude(), location.getLongitude()));
}
private void writeLastLocation() {
writeActualLocation(lastLocation);
}
private Marker locationMarker;
private void markerLocation(LatLng latLng) {
Log.i(TAG, "markerLocation(" + latLng + ")");
String title = latLng.latitude + ", " + latLng.longitude;
MarkerOptions markerOptions = new MarkerOptions()
.position(latLng)
.title(title);
if (map != null) {
if (locationMarker != null)
locationMarker.remove();
locationMarker = map.addMarker(markerOptions);
float zoom = 14f;
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, zoom);
map.animateCamera(cameraUpdate);
}
}
// Start Geofence creation process
private void startGeofence() {
Log.i(TAG, "startGeofence()");
Geofence geofence = createGeofence();
GeofencingRequest geofenceRequest = createGeofenceRequest(geofence);
addGeofence(geofenceRequest);
}
private static final long GEO_DURATION = 60 * 60 * 1000;
private static final String GEOFENCE_REQ_ID = "My Geofence";
private static final float GEOFENCE_RADIUS = 200.0f; // in meters
// Create a Geofence
private Geofence createGeofence() {
Log.d(TAG, "createGeofence");
return new Geofence.Builder()
.setRequestId(GEOFENCE_REQ_ID)
.setCircularRegion(18.478122, 73.890158, GEOFENCE_RADIUS)
.setExpirationDuration(GEO_DURATION)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_EXIT)
.build();
}
// Create a Geofence Request
private GeofencingRequest createGeofenceRequest(Geofence geofence) {
Log.d(TAG, "createGeofenceRequest");
return new GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.addGeofence(geofence)
.build();
}
private PendingIntent geoFencePendingIntent;
private static final int GEOFENCE_REQ_CODE = 0;
private PendingIntent createGeofencePendingIntent() {
Log.d(TAG, "createGeofencePendingIntent");
if (geoFencePendingIntent != null)
return geoFencePendingIntent;
Intent intent = new Intent(this, GeofenceTrasitionService.class);
return PendingIntent.getService(
this, GEOFENCE_REQ_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
// Add the created GeofenceRequest to the device's monitoring list
private void addGeofence(GeofencingRequest request) {
Log.d(TAG, "addGeofence");
if (checkPermission())
LocationServices.GeofencingApi.addGeofences(
googleApiClient,
request,
createGeofencePendingIntent()
).setResultCallback(this);
}
#Override
public void onResult(#NonNull Status status) {
Log.i(TAG, "onResult: " + status);
if (status.isSuccess()) {
drawGeofence();
} else {
// inform about fail
}
}
// Draw Geofence circle on GoogleMap
private Circle geoFenceLimits;
private void drawGeofence() {
Log.d(TAG, "drawGeofence()");
if (geoFenceLimits != null)
geoFenceLimits.remove();
CircleOptions circleOptions = new CircleOptions()
.center(new LatLng(18.478122, 73.890158))
.strokeColor(Color.argb(50, 70, 70, 70))
.fillColor(Color.argb(100, 150, 150, 150))
.radius(GEOFENCE_RADIUS);
geoFenceLimits = map.addCircle(circleOptions);
}
private final String KEY_GEOFENCE_LAT = "GEOFENCE LATITUDE";
private final String KEY_GEOFENCE_LON = "GEOFENCE LONGITUDE";
// Saving GeoFence marker with prefs mng
private void saveGeofence() {
Log.d(TAG, "saveGeofence()");
SharedPreferences sharedPref = getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
// editor.putLong(KEY_GEOFENCE_LAT, Double.doubleToRawLongBits(geoFenceMarker.getPosition().latitude));
// editor.putLong(KEY_GEOFENCE_LON, Double.doubleToRawLongBits(geoFenceMarker.getPosition().longitude));
editor.apply();
}
// Recovering last Geofence marker
private void recoverGeofenceMarker() {
drawGeofence();
}
// Clear Geofence
private void clearGeofence() {
Log.d(TAG, "clearGeofence()");
LocationServices.GeofencingApi.removeGeofences(
googleApiClient,
createGeofencePendingIntent()
).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
if (status.isSuccess()) {
// remove drawing
removeGeofenceDraw();
}
}
});
}
private void removeGeofenceDraw() {
Log.d(TAG, "removeGeofenceDraw()");
}
}
To get notification:-
public class GeofenceTrasitionService extends IntentService {
private static final String TAG = GeofenceTrasitionService.class.getSimpleName();
public static final int GEOFENCE_NOTIFICATION_ID = 0;
public GeofenceTrasitionService() {
super(TAG);
}
#Override
protected void onHandleIntent(Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
// Handling errors
if ( geofencingEvent.hasError() ) {
String errorMsg = getErrorString(geofencingEvent.getErrorCode() );
Log.e( TAG, errorMsg );
return;
}
int geoFenceTransition = geofencingEvent.getGeofenceTransition();
// Check if the transition type is of interest
if (geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT ) {
// Get the geofence that were triggered
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
String geofenceTransitionDetails = getGeofenceTrasitionDetails(geoFenceTransition, triggeringGeofences );
// Send notification details as a String
sendNotification( geofenceTransitionDetails );
}
}
private String getGeofenceTrasitionDetails(int geoFenceTransition, List<Geofence> triggeringGeofences) {
// get the ID of each geofence triggered
ArrayList<String> triggeringGeofencesList = new ArrayList<>();
for ( Geofence geofence : triggeringGeofences ) {
triggeringGeofencesList.add( geofence.getRequestId() );
}
String status = null;
if ( geoFenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT )
status = "Exiting ";
return status + TextUtils.join( ", ", triggeringGeofencesList);
}
private void sendNotification( String msg ) {
Log.i(TAG, "sendNotification: " + msg );
// Intent to start the main Activity
Intent notificationIntent = MainActivity.makeNotificationIntent(
getApplicationContext(), msg
);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(notificationIntent);
PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Creating and sending Notification
NotificationManager notificatioMng =
(NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE );
notificatioMng.notify(
GEOFENCE_NOTIFICATION_ID,
createNotification(msg, notificationPendingIntent));
}
// Create notification
private Notification createNotification(String msg, PendingIntent notificationPendingIntent) {
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
notificationBuilder
.setSmallIcon(R.drawable.ic_action_location)
.setColor(Color.RED)
.setContentTitle(msg)
.setContentText("Geofence Notification!")
.setContentIntent(notificationPendingIntent)
.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)
.setAutoCancel(true);
return notificationBuilder.build();
}
private static String getErrorString(int errorCode) {
switch (errorCode) {
case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
return "GeoFence not available";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
return "Too many GeoFences";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
return "Too many pending intents";
default:
return "Unknown error.";
}
}
}
As per tutorial i see:- there are 3 notification trigger
1.Enter 2.Dwell 3.Exit
I dont know how did i get notified when it leave the fence so far as in code i tried Exit.But no luck.
Ok i understand so just need to change the function :-
private GeofencingRequest createGeofenceRequest(Geofence geofence) {
Log.d(TAG, "createGeofenceRequest");
return new GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_EXIT)
.addGeofence(geofence)
.build();
}
Here i did changed My initial trigger with Exit
"GeofencingRequest.INITIAL_TRIGGER_EXIT"
and got perfect output.
This work for both enter and exit
private GeofencingRequest createGeofenceRequest(Geofence geofence) {
return new GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_EXIT|GeofencingRequest.INITIAL_TRIGGER_ENTER)
.addGeofence(geofence)
.build();
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 a newbie to Android and working on my very first application. I am working on a application which takes continuous location update and show that on google map. It means no matter whether application is in foreground or in background.
For the same I am using fusedlocation API's requestLocationUpdates. There are two version of the same viz:
With LocationListener when app is in foreground
With pendingIntent when app goes to background.
So as per my understanding I have to use both as I need continuous update.So I am using both in my application as I need continuous update.
But as a surprise I got that requestLocationUpdates with pendingIntent giving me location update in foreground as well. So I am very confused here and sometime giving Location as NULL .
Please tell me what is the exact behaviour of requestLocationUpdates with pendingIntent . Will it work for both foreground and bckground ? If yes then why I am getting the Location as NULL sometime.
Another problem when I was using Locationreveiver then I was able toget proper location update when app was in foreground and I was drawing a line on googlemap. But I noticed my line was not in sync with googlemap route. It was zig zag . So here I am confused If I am getting continuous update then why not m route is sync with google route .
I am attaching the complecode of my location class. Please help
public class LocationMapsActivity extends FragmentActivity implements
LocationListener,
OnMapReadyCallback,
GoogleApiClient.ConnectionCallbacks,
ComponentCallbacks2,
GoogleApiClient.OnConnectionFailedListener {
//*******************************member variables*********************************************
private static final String TAG = "LocationActivity";
private static final long INTERVAL = 1000 *02; // 1000*60*1 = 1 minute
private static final long FASTEST_INTERVAL = 1000 *01 ;// 10 sec
public static LatLng mPrev = null;
private double mCurrentDistance = 0;
private double mTotalDistance = 0;
private double mCurrentSpeed = 0;
public static String stateOfLifeCycle = "";
public static boolean wasInBackground = false;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mCurrentLocation;
Location mStartLocation;
GoogleMap googleMap;
//********************************************
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate ...............................");
wasInBackground = false;
stateOfLifeCycle = "Create";
//show error dialog if GoolglePlayServices not available
if (!isGooglePlayServicesAvailable()) {
finish();
}
createLocationRequest();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
setContentView(R.layout.activity_map_location);
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
//*******************ComponentCallbacks2*************************
#Override
public void onTrimMemory(int level) {
if (stateOfLifeCycle.equals("Stop")) {
wasInBackground = true;
}
super.onTrimMemory(level);
Toast.makeText(getApplicationContext(),
"Application OnTrimmemory ", Toast.LENGTH_SHORT)
.show();
}
//****************Activity****************************
#Override
public void onStart() {
Toast.makeText(getApplicationContext(),"OnStart ", Toast.LENGTH_SHORT).show();
Log.d(TAG, "onStart fired ..............");
stateOfLifeCycle = "Start";
if (wasInBackground) {
Toast.makeText(getApplicationContext(),"Application came to foreground",Toast.LENGTH_SHORT).show();
wasInBackground = false;
}
super.onStart();
if(!mGoogleApiClient.isConnected())
mGoogleApiClient.connect();
}
//********************Activity************************
#Override
public void onStop() {
stateOfLifeCycle = "Stop";
Log.d(TAG, "onStop fired ..............");
stopLocationUpdates();
// mGoogleApiClient.disconnect();
super.onStop();
Toast.makeText(getApplicationContext(), "OnStop ", Toast.LENGTH_SHORT).show();
Log.d(TAG, "isConnected ...............: " + mGoogleApiClient.isConnected());
}
//**************Activity******************************
#Override
protected void onPause() {
stateOfLifeCycle = "Pause";
super.onPause();
Toast.makeText(getApplicationContext(), "OnPause ", Toast.LENGTH_SHORT) .show();
}
//*******************Activity*************************
#Override
public void onResume() {
Toast.makeText(getApplicationContext(),"OnResume ", Toast.LENGTH_SHORT).show();
stateOfLifeCycle = "Resume";
super.onResume();
if (mGoogleApiClient.isConnected()) {
startLocationUpdates();
Log.d(TAG, "Location update resumed .....................");
}
}
//*****************Activity***************************
#Override
public void onDestroy()
{
wasInBackground = false;
stateOfLifeCycle = "Destroy";
super.onDestroy();
Toast.makeText(getApplicationContext(), "Application OnDestroy ", Toast.LENGTH_SHORT).show();
}
//******************OnMapReadyCallback**************************
#Override
public void onMapReady(GoogleMap map) {
googleMap = map;
googleMap.setMyLocationEnabled(true);
googleMap.getUiSettings().setZoomControlsEnabled(true);
//googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
}
//*******************GoogleApiClient.ConnectionCallbacks*************************
#Override
public void onConnected(Bundle bundle) {
Log.d(TAG, "onConnected - isConnected ...............: " + mGoogleApiClient.isConnected());
startLocationUpdates();
}
//*******************GoogleApiClient.ConnectionCallbacks*************************
#Override
public void onConnectionSuspended(int i) {
}
//*****************GoogleApiClient.ConnectionCallbacks***************************
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.d(TAG, "Connection failed: " + connectionResult.toString());
}
//*****************LocationListener***************************
// #Override
public void onLocationChanged(Location location) {
Log.d(TAG, "Firing onLocationChanged..............................................");
mCurrentLocation = location;
LatLng current = new LatLng(location.getLatitude(), location.getLongitude());
if(mPrev == null) //when the first update comes, we have no previous points,hence this
{
mPrev=current;
mStartLocation = location;
addMarker();
}
else {
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(current, 17);
googleMap.animateCamera(update);
PolylineOptions pOptions = new PolylineOptions()
.width(7)
.color(Color.BLUE)
.visible(true);// .geodesic(true)
pOptions.add(mPrev);
pOptions.add(current);
googleMap.addPolyline(pOptions);
mPrev = current;
current = null;
}
}
//********************************************
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
//********************************************
private boolean isGooglePlayServicesAvailable() {
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (ConnectionResult.SUCCESS == status) {
Log.d(TAG, "isGooglePlayServicesAvailable ...............: SUCCESS" );
return true;
} else {
GooglePlayServicesUtil.getErrorDialog(status, this, 0).show();
return false;
}
}
//********************************************
protected void startLocationUpdates() {
//Get foreground location update
/* PendingResult<Status> pendingResult = LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);*/
//Get background location update
String proximitys = "ACTION";
IntentFilter filter = new IntentFilter(proximitys);
getApplicationContext().registerReceiver(new LocationReceiver() , filter);
Intent intent = new Intent(proximitys);
// Intent intent = new Intent(this, LocationReceiver.class);
PendingIntent locationIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, locationIntent);
}
//********************************************
public void HandleLocationChanged(Location location) {
Log.d(TAG, "Firing HandleLocationChanged..............................................");
// Toast.makeText(getApplicationContext(), "HandleLocationChanged", Toast.LENGTH_LONG).show();
if(location == null)
{
Toast.makeText(getApplicationContext(), "location is null", Toast.LENGTH_LONG).show();
return;
}
mCurrentLocation = location;
LatLng current = new LatLng(location.getLatitude(), location.getLongitude());
if(mPrev == null) //when the first update comes, we have no previous points,hence this
{
mPrev=current;
mStartLocation = location;
addMarker();
}
else {
CameraUpdate update = CameraUpdateFactory.newLatLngZoom(current, 17);
googleMap.animateCamera(update);
PolylineOptions pOptions = new PolylineOptions()
.width(7)
.color(Color.BLUE)
.visible(true);// .geodesic(true)
pOptions.add(mPrev);
pOptions.add(current);
googleMap.addPolyline(pOptions);
mPrev = current;
current = null;
}
}
//********************************************
public String getAddress( )
{
Geocoder geocoder = new Geocoder(this);
String addressLineTemp=null;
List<Address> addresses;
try {
addresses = geocoder.getFromLocation(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude(), 1);
if (addresses.size() > 0) {
addressLineTemp = addresses.get(0).getAddressLine(0);
}
} catch (IOException e) {
e.printStackTrace();
}
return addressLineTemp;
}
//********************************************
private void addMarker() {
MarkerOptions options = new MarkerOptions();
LatLng currentLatLng = new LatLng(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude());
options.position(currentLatLng);
Marker mapMarker = googleMap.addMarker(options);
mapMarker.setTitle(getAddress());
Log.d(TAG, "Marker added.............................");
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng,
13));
Log.d(TAG, "Zoom done.............................");
}
//********************************************
protected void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, this);
Log.d(TAG, "Location update stopped .......................");
}
//********************************************
public class LocationReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
Log.d(TAG, "Firing LocationReceiver....onReceive..........................................");
Location location = (Location) intent.getExtras().get(LocationServices.FusedLocationApi.KEY_LOCATION_CHANGED);
HandleLocationChanged(location);
}
}