I am developing an android app that uses gms play services geofencing API to send some data to a server whenever the user enters a geofence. The app is working fine for geofences where there is wifi connectivity. My intentservice is not getting started for geofences without wifi connectivity even if the location is fixed in this geofence( i checked it using the maps app on the same device). I think this problem has nothing to do with geofence radius as i tested with 300 meters( it says 100-150 will work good in the documentation). In developer.android.com it says "Having Wi-Fi on can significantly improve the location accuracy, so if Wi-Fi is turned off, your application might never get geofence alerts depending on several settings including the radius of the geofence, the device model, or the Android version.". I am using symphony v75 as testing device and the android version is marshmallow. does this anything to do with it. If someone here faced similar problem please help. Here is the service where i create the geofences.
public class sendLocation extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<Status> {
dbCreate dbcreate;
SQLiteDatabase db;
private String empId;
public static final float GEOFENCE_RADIUS_IN_METERS = 300;
protected ArrayList<Geofence> mGeofenceList;
protected GoogleApiClient mGoogleApiClient;
public static final HashMap<String, LatLng> LANDMARKS = new HashMap<String, LatLng>();
private ScheduledExecutorService scheduledExecutorService;
private String logUrl="https://abdulhalim.pythonanywhere.com/rams/default/get_att_log.json";
//private String logUrl="https://rumytechnologies.com/ramsm/default/get_att_log.json";
public String Tag="newtag";
private boolean myDeletePermission=false;
dbUnitSuper dbunit;
public String unitUri="https://abdulhalim.pythonanywhere.com/rams/default/getUnits.json?client_id=";
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
//buildGoogleApiClient();
mGoogleApiClient=new GoogleApiClient.Builder(getApplicationContext())
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
//dbcreate=dbCreate.getInstance(this);
dbunit=dbUnitSuper.getInstance(sendLocation.this);
empId=dbunit.readEmpId();
mGeofenceList = new ArrayList<Geofence>();
populateGeofenceList();
Log.d(Tag,"populate geofencelist is called on oncreate of service");
scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleWithFixedDelay(startSend,3,3, TimeUnit.MINUTES);
}
Runnable startSend=new Runnable() {
@Override
public void run() {
Log.d(Tag,"runnable is running");
//String[] projection={dbcreate.UNITID};
//Cursor C=db.query(dbcreate.TB_name,projection,null,null,null,null,null);
ArrayList<String> unitIds=new ArrayList<>();
dbBufferSuper dbBuffer=dbBufferSuper.getInstance(sendLocation.this);
unitIds=dbunit.readUnitIds();
if(isOnLine())
{ for(int i=0;i<unitIds.size();i++) {
String loopUnitID = unitIds.get(i);
JSONObject unitJson = dbBuffer.readBufferLog(loopUnitID);
if (unitJson != null) {
sendLog send = new sendLog();
send.execute(unitJson);
} else {
Log.d(Tag, "unitjson returns null for unit "+i);
}
}
getUnitUpdate unitUpdate=new getUnitUpdate();
unitUpdate.execute(empId);}
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (!mGoogleApiClient.isConnecting() || !mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mGoogleApiClient.isConnecting() || mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
protected boolean isOnLine()
{
ConnectivityManager cm= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo=cm.getActiveNetworkInfo();
if(netInfo!=null&& netInfo.isConnectedOrConnecting())
{
return true;
}
else
{
return false;
}
}
public void populateLandmark(){
dbUnitSuper dbunit=dbUnitSuper.getInstance(this);
ArrayList<ArrayList<String>> unitInfo=dbunit.readUnitInformation();
if(unitInfo!=null) {
for(int i=0;i<unitInfo.size();i++)
{
ArrayList<String> singleUnit=unitInfo.get(i);
LANDMARKS.put(singleUnit.get(0),
new LatLng(Float.parseFloat(singleUnit.get(1)), Float.parseFloat(singleUnit.get(2))));}
}
}
public void populateGeofenceList() {
populateLandmark();
for (Map.Entry<String, LatLng> entry : LANDMARKS.entrySet()) {
mGeofenceList.add(new Geofence.Builder()
.setRequestId(entry.getKey())
.setCircularRegion(
entry.getValue().latitude,
entry.getValue().longitude,
GEOFENCE_RADIUS_IN_METERS
)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setLoiteringDelay(15000)
.setNotificationResponsiveness(30000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_DWELL)
.build());
}
int i=mGeofenceList.size();
Log.d(Tag,"number of geofences entered in the geofence list is "+i);
}
@Override
public void onConnected(@Nullable Bundle bundle) {
try {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult().
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
Log.d(Tag," securityException occured while adding in onconnected");
}
}
@Override
public void onConnectionSuspended(int i) {
mGoogleApiClient.connect();
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_DWELL);
builder.addGeofences(mGeofenceList);
return builder.build();
}
private PendingIntent getGeofencePendingIntent() {
Intent intent = new Intent(sendLocation.this, GeofenceTransitionsIntentService.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling addgeoFences()
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
@Override
public void onResult(@NonNull Status status) {
}
private class pollTask extends AsyncTask<String,Void,String>{
@Override
protected String doInBackground(String... params) {
return null;
}
}
private class getUnitUpdate extends AsyncTask<String,Void,String> implements ResultCallback<Status> {
HttpsURLConnection https;
@Override
protected String doInBackground(String... params) {
InputStreamReader inputStream = null;
BufferedReader reader = null;
StringBuilder newSb=new StringBuilder();
newSb.append(unitUri);
newSb.append(params[0]);
try {
URL url=new URL(newSb.toString());
https=(HttpsURLConnection) url.openConnection();
if(https==null)
{Log.d(Tag,"urlconnection returns null");}
https.setRequestMethod("GET");
https.setDoInput(true);
int status =https.getResponseCode();
Log.d(Tag, "getunits Status : " + status);
inputStream = new InputStreamReader(https.getInputStream());
reader = new BufferedReader(inputStream);
StringBuilder message = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
message.append(line);
}
return message.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
https.disconnect();
}
return null;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.d(Tag," updated units are"+s);
try {
JSONObject jsonRootObject=new JSONObject(s);
JSONArray jsonlatArray=jsonRootObject.optJSONArray("Latitude");
JSONArray jsonlonArray=jsonRootObject.optJSONArray("Longitude");
JSONArray jsonuniArray=jsonRootObject.optJSONArray("Unit_Id");
dbUnitSuper unitSuper=dbUnitSuper.getInstance(sendLocation.this);
ArrayList<String> unitIds=unitSuper.readUnitIds();
if(jsonuniArray.length()!=unitIds.size()){
//String empId= unitSuper.readEmpId();
//delete the rows in unit database
int del= unitSuper.deleteAllUnitInfo();
Log.d(Tag,"number of deleted unit rows are"+del);
//populate the unit database again
for(int i=0;i<jsonlatArray.length();i++){
String unit_id=jsonuniArray.getString(i);
String latitude=jsonlatArray.getString(i);
String longitude=jsonlonArray.getString(i);
long intest= unitSuper.insertData(empId,unit_id,latitude,longitude);
if(intest<0){
// Toast.makeText(MainActivity.this, "insert unsuccessful", Toast.LENGTH_LONG).show();
String rt=Integer.toString(i);
Log.d(Tag,"insert unsuccessful "+rt);
}
else{
// Toast.makeText(MainActivity.this, "successfully inserted a row", Toast.LENGTH_LONG).show();
String rt=Integer.toString(i);
Log.d(Tag,"successfully inserted a row "+rt);
}
}
/*remove geofences here
removeGeofences();
//clear mgeofencelist arraylist
if(mGeofenceList.size()>0){
mGeofenceList.clear();
}
//recreate the geofences
populateGeofenceList();*/
}else{
Log.d(Tag,"no new units are added or deleted");
}
} catch (JSONException e) {
e.printStackTrace();
}
/*if (!mGoogleApiClient.isConnecting() || !mGoogleApiClient.isConnected()) {
Log.d(Tag," entered the if block to recreate the geofences");
mGoogleApiClient.connect();
}
else {
Log.d(Tag," entered the else block to recreate the geofences");
try {
Log.d(Tag," entered the try block to recreate the geofences");
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
getGeofencingRequest(),
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult().
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
Log.d(Tag,"sequrity exception occured at unit updaate while creating neew geofences");
}
}*/
}
@Override
public void onResult(@NonNull com.google.android.gms.common.api.Status status) {
Log.d(Tag,"geofences recreated successfully");
}
}
private void removeGeofences(){
LocationServices.GeofencingApi.removeGeofences(
mGoogleApiClient,
// This is the same pending intent that was used in addGeofences().
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult().
}
private class sendLog extends AsyncTask<JSONObject,Void,String>{
HttpsURLConnection https;
String loopUnitID;
@Override
protected String doInBackground(JSONObject... params) {
InputStreamReader inputStream = null;
BufferedReader reader = null;
JSONObject parseUnitIdJson=params[0];
JSONObject rows=parseUnitIdJson.optJSONObject("Row");
loopUnitID=rows.optString("unit_id");
Log.d(Tag,"the unit id parsed in sendlog is "+loopUnitID);
String postStr=String.format(params[0].toString());
try {
URL url=new URL(logUrl);
https=(HttpsURLConnection) url.openConnection();
https.setRequestMethod("POST");
https.setDoInput(true);
https.setDoOutput(true);
OutputStreamWriter writer=new OutputStreamWriter(https.getOutputStream());
writer.write(postStr);
writer.flush();
Log.d(Tag,"data flushed succesfully");
int status =https.getResponseCode();
Log.d(Tag, "Status : " + status);
inputStream = new InputStreamReader(https.getInputStream());
reader = new BufferedReader(inputStream);
StringBuilder message = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
message.append(line);
}
Log.d(Tag,"sendLog returns"+message.toString());
return message.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
https.disconnect();
}
return null;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
try {
dbBufferSuper dbBuffer=dbBufferSuper.getInstance(sendLocation.this);
JSONObject sendResult=new JSONObject(s);
JSONArray suck=sendResult.optJSONArray("result");
Log.d(Tag,"the value read from result is "+suck.get(0));
if(suck.get(0).equals("success")){
Log.d(Tag,"permission granted for deleting a units log i");
int status= dbBuffer.deleteRows(loopUnitID);
if(status>0){
Log.d(Tag,"the number of affected rows in deletebufferrows is "+status);
}
// myDeletePermission=false;
/*myDeletePermission=true;
if(myDeletePermission==true){
Log.d(Tag,"delete permission is set to true");
}else{
Log.d(Tag,"delete permission is still false after getting success");
}*/
}else {Log.d(Tag,"success is not extracted properly from the json response of sendlog");}
} catch (JSONException e) {
e.printStackTrace();
Log.d(Tag,"failed to instantiate getattlogs response as json" );
}
}
}
}