0

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" );
        }
    }
}
  }
  • `Having Wi-Fi on can significantly improve the location accuracy,`. You should not believe this nonsense. Yes in a building when there is no gps sigal from satelites. But outside only a gps is accurate. – greenapps Oct 25 '16 at 21:44
  • It is very unclear who is checking if the location of your device is in a geofence. Please tell who is doing that. Make sure to tell if wifi is needed for that or not. – greenapps Oct 25 '16 at 21:51
  • I am using the google maps app in my device to check whether my device is in the geofence. The maps app shows me i am in the geofence, it actually shows my current location almost accurately. And no wifi connection is needed for this. – Tamjid Rayhan Oct 26 '16 at 03:35
  • Forget the Maps app please. You only confuse me. My question was about your app. Now please tell who/where/how is checked if the device enters a geofence. Is wifi needed for that? Or a mobile connection? – greenapps Oct 26 '16 at 08:34
  • I am creating a GoogleApiClient which requests the google play services app to check whether the devices location is within a registered geofence. I don't know whether the google play services app needs wifi connecction to do this but i think it does not. I think that as i made another app where i retrieve devices last known location using the google play services it did not require wifi. – Tamjid Rayhan Oct 26 '16 at 09:02
  • Why arent you sure? Find out first. If wifi is not needed then why your intent service is not started? What goes different snd where? You should debug better. – greenapps Oct 26 '16 at 09:08

1 Answers1

1

If you're app doesn't have wifi connectivity, please make sure that you have reliable data connection to be able to still use Geofence.

As already mentioned in the documentation that you have,

If there is no reliable data connection, alerts might not be generated. This is because the geofence service depends on the network location provider which in turn requires a data connection.

Furthermore, if you prefer turning off your wifi, use SettingsApi to ensure that the device's system settings are properly configured for optimal location detection.

Please also check SettingsAPI wherein it was mentioned that,

When making a request to location services, the device's system settings may be in a state that prevents an app from obtaining the location data that it needs. For example, GPS or Wi-Fi scanning may be switched off.

Please try going through the given documentations and you may also opt to check responses in this SO post - How do I use the Android Geofencing API?. Hope the helps!

Community
  • 1
  • 1
Teyam
  • 7,686
  • 3
  • 15
  • 22
  • The first paragraph "If you're (sic) app doesn't have wifi connectivity, please make sure that you have reliable data connection to be able to still use Geofence".... is basically incorrect and at the very least misleading. You don't need wifi or data connectivity to use Geofencing. – Simon Hutton Dec 01 '16 at 01:33