1

How to Create Geo fence(Creating and Monitoring Geo fences) on current latitude,longitude. I am trying multiple example but not create. Using this code:

public Geofence geofence(float radius, double latitude, double longitude) {
    String id = UUID.randomUUID().toString();
    return new Geofence.Builder()
            .setRequestId(id)
            .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
            .setCircularRegion(latitude, longitude, radius)
            .setExpirationDuration(Geofence.NEVER_EXPIRE)
            .build();
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
RAKESH DADHICH
  • 326
  • 1
  • 4
  • 11

2 Answers2

2

There's this tutorial from Google, that's very easy to follow:

http://io2015codelabs.appspot.com/codelabs/geofences

There's also a course at Udacity that teaches location services, including geofences:

https://www.udacity.com/course/google-location-services-on-android--ud876-1

Add Google Play Services to Gradle File:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.0.0'
    compile 'com.google.android.gms:play-services:7.3.0'
}

Add to Manifest File:

<meta-data
    android:name="com.google.android.gms.version"
    android:value="@integer/google_play_services_version" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

Add to Activity's XML Layout file:

<Button
        android:id="@+id/add_geofences_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:onClick="addGeofencesButtonHandler"
        android:text="Add GeoFences" />

Add to Activity's Java File:

public class MainActivity extends Activity
implements
GoogleApiClient.ConnectionCallbacks, 
GoogleApiClient.OnConnectionFailedListener, 
ResultCallback<Status>{ 

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mAddGeofencesButton = (Button) findViewById(R.id.add_geofences_button);
        // Empty list for storing geofences.
        mGeofenceList = new ArrayList<Geofence>();

        // Get the geofences used. Geofence data is hard coded in this sample.
        populateGeofenceList();

        // Kick off the request to build GoogleApiClient.
        buildGoogleApiClient();
    }

protected synchronized void buildGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    }

public void populateGeofenceList() {
for (Map.Entry<String, LatLng> entry : Constants.LANDMARKS.entrySet()) {
mGeofenceList.add(new Geofence.Builder()
   .setRequestId(entry.getKey())
   .setCircularRegion(
   entry.getValue().latitude,
   entry.getValue().longitude,
   Constants.GEOFENCE_RADIUS_IN_METERS
   )
   .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)
   .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
   Geofence.GEOFENCE_TRANSITION_EXIT)
   .build());
   }
}

@Override
protected void onStart() {
    super.onStart();
    if (!mGoogleApiClient.isConnecting() || !mGoogleApiClient.isConnected()) {
        mGoogleApiClient.connect();
    }
}

@Override
protected void onStop() {
    super.onStop();
    if (mGoogleApiClient.isConnecting() || mGoogleApiClient.isConnected()) {
        mGoogleApiClient.disconnect();
    }
}

@Override
public void onConnected(Bundle connectionHint) {

}

@Override
public void onConnectionFailed(ConnectionResult result) {
    // Do something with result.getErrorCode());
}

@Override
public void onConnectionSuspended(int cause) {
    mGoogleApiClient.connect();
}

    public void addGeofencesButtonHandler(View view) {
            if (!mGoogleApiClient.isConnected()) {
                Toast.makeText(this, "Google API Client not connected!", Toast.LENGTH_SHORT).show();
                return;
            }

            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.
            }
    }

   private GeofencingRequest getGeofencingRequest() {
        GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
        builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
        builder.addGeofences(mGeofenceList);
        return builder.build();
    }

    private PendingIntent getGeofencePendingIntent() {
            Intent intent = new Intent(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);
        }

public void onResult(Status status) {
        if (status.isSuccess()) {
            Toast.makeText(
                    this,
                    "Geofences Added",
                    Toast.LENGTH_SHORT
            ).show();
        } else {
            // Get the status code for the error and log it using a user-friendly message.
            String errorMessage = GeofenceErrorMessages.getErrorString(this,
                    status.getStatusCode());
        }
    }

Create a java file called Constans:

public class Constants {

    public static final long GEOFENCE_EXPIRATION_IN_MILLISECONDS = 12 * 60 * 60 * 1000;
    public static final float GEOFENCE_RADIUS_IN_METERS = 20;

    public static final HashMap<String, LatLng> LANDMARKS = new     HashMap<String, LatLng>();
    static {
        // San Francisco International Airport.
        LANDMARKS.put("Moscone South", new LatLng(37.783888,-122.4009012));

        // Googleplex.
        LANDMARKS.put("Japantown", new LatLng(37.785281,-122.4296384));

        // Test
        LANDMARKS.put("SFO", new LatLng(37.621313,-122.378955));
    }
}

Create a java file called GeofenceTransitionsIntentService:

public class GeofenceTransitionsIntentService extends IntentService {
  protected static final String TAG = "GeofenceTransitionsIS";

  public GeofenceTransitionsIntentService() {
    super(TAG);  // use TAG to name the IntentService worker thread
  }

  @Override
  protected void onHandleIntent(Intent intent) {
    GeofencingEvent event = GeofencingEvent.fromIntent(intent);
    if (event.hasError()) {
      Log.e(TAG, "GeofencingEvent Error: " + event.getErrorCode());
      return;
    }
  }

 String description = getGeofenceTransitionDetails(event);
   sendNotification(description);
 }

   private static String getGeofenceTransitionDetails(GeofencingEvent event) {
String transitionString =
    GeofenceStatusCodes.getStatusCodeString(event.getGeofenceTransition());
List triggeringIDs = new ArrayList();
for (Geofence geofence : event.getTriggeringGeofences()) {
  triggeringIDs.add(geofence.getRequestId());
}
return String.format("%s: %s", transitionString, TextUtils.join(", ", triggeringIDs));
}

  private void sendNotification(String notificationDetails) {
    // Create an explicit content Intent that starts MainActivity.
    Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);

    // Get a PendingIntent containing the entire back stack.
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
    stackBuilder.addParentStack(MainActivity.class).addNextIntent(notificationIntent);
    PendingIntent notificationPendingIntent =
        stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

    // Get a notification builder that's compatible with platform versions >= 4
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this);

    // Define the notification settings.
    builder.setColor(Color.RED)
        .setContentTitle(notificationDetails)
        .setContentText("Click notification to return to App")
        .setContentIntent(notificationPendingIntent)
        .setAutoCancel(true);

    // Fire and notify the built Notification.
    NotificationManager notificationManager =
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.notify(0, builder.build());
  }

You should probably stick to their tutorial instead of copying and pasting the code to your project :D

Source

Pang
  • 9,564
  • 146
  • 81
  • 122
Punpuf
  • 2,042
  • 1
  • 19
  • 30
  • In onResult, is there suppose to be @Override at the top? And im going red text at `GeofenceErrorMessages` in `GeofenceErrorMessages.getErrorString(this, status.getStatusCode());` I cant find GeoFenceErrorMessages class – TheQ Sep 24 '16 at 19:29
  • Hi, the @Override is necessary, because it will be overriding the default method implementation of onResult. The GeoFenceErrorMessages class is a custom class created to get the error id of the geofence and return a an error message, this part is not necessary for the geofence to work, but it's a good practice, more information can be found at this course at Udacity: https://www.udacity.com/course/google-location-services-on-android--ud876-1 – Punpuf Sep 25 '16 at 01:39
  • @MarcolaCarr do we need to declare GeofenceTransitionsIntentService in manifest file under application tag? – xaif Oct 25 '19 at 03:00
0

I am doing it in a Service

GeolocationService

    public class GeolocationService extends Service implements LocationListener,
        GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {

    private Context mContext;
    private GoogleApiClient mGoogleApiClient;
    private LocationRequest mLocationRequest;
//    private Location mLastLocation;
    private PendingIntent mGeofencePendingIntent;
    private String mLastUpdateTime;
    public static boolean isGeoFenceAdded = false;
    private boolean mUpdateGeoFence = false;
    private boolean mRemoveAllGeoFence = false;

    private static final long TIME_OUT = 100;

    @Override
    public void onCreate() {
        super.onCreate();

        mContext = GeolocationService.this;
        buildGoogleApiClient();
        createLocationRequest();

    }

    protected synchronized void buildGoogleApiClient() {
        mGoogleApiClient = new GoogleApiClient.Builder(mContext)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
        /// FIXME: 2/15/2017 connect should be handled through onStart and onStop of Activity
        mGoogleApiClient.connect();
    }

    protected void createLocationRequest() {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(5000);//set the interval in which you want to get locations
        mLocationRequest.setFastestInterval(2500);//if a location is available sooner you can get it (i.e. another app is using the location services)
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null) {
            if (intent.getAction() != null) {
                if (intent.getAction().equals(Constants.ACTION_UPDATE_GEOFENCE)) {
                    //// FIXME: 3/21/2017 you can also receive triggered location here..
                    mUpdateGeoFence = true;
                    isGeoFenceAdded = false;
                    mRemoveAllGeoFence = false;
                } else if (intent.getAction().equals(Constants.ACTION_ADD_GEOFENCE)) {
                    mUpdateGeoFence = false;
                    isGeoFenceAdded = false;
                    mRemoveAllGeoFence = false;
                } else if (intent.getAction().equals(Constants.ACTION_REMOVE_ALL_GEOFENCE)) {
                    mRemoveAllGeoFence = true;
                    isGeoFenceAdded = true;
                    mUpdateGeoFence = false;
                }
            }
        }
        //try this for null as http://stackoverflow.com/a/25096022/3496570
        ///return START_REDELIVER_INTENT;
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        startLocationUpdates(mContext);
    }

    @Override
    public void onConnectionSuspended(int i) {
        switch (i) {
            case CAUSE_SERVICE_DISCONNECTED:
                /*if (onLocationUpdateListener != null)
                    onLocationUpdateListener.onError(
                            Constants.ErrorType.SERVICE_DISCONNECTED);*/
                break;
            case CAUSE_NETWORK_LOST:
                /*if (onLocationUpdateListener != null)
                    onLocationUpdateListener.onError(
                            Constants.ErrorType.NETWORK_LOST);*/
                break;
        }

        //// FIXME: 3/2/2017 check is it right to check for re Connecting..
        //---  http://stackoverflow.com/a/27350444/3496570
        ///mGoogleApiClient.connect();
    }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
        /*if (onLocationUpdateListener != null)
            onLocationUpdateListener.onError(
                    Constants.ErrorType.CONNECTION_FAIL);*/

        //// FIXME: 3/3/2017 call a transparent activity and call startResolutionForresult from their and return result to service using action
        if (connectionResult.hasResolution()) {
            /*try {
                // !!!
                connectionResult.startResolutionForResult(this, REQUEST_CODE_RESOLVE_ERR);
            } catch (IntentSender.SendIntentException e) {
                e.printStackTrace();
            }*/
        } else {
            /*GoogleApiAvailability.getInstance().getErrorDialog(mContext, connectionResult.getErrorCode(), 0).show();
            return;*/
        }
    }

    @Override
    public void onLocationChanged(final Location currentLocation) {
        setupGeoFencePoints(currentLocation);
        /*if (onLocationUpdateListener != null && mLocation != null) {
            onLocationUpdateListener.onLocationChange(mLocation);
        }*/
    }

    private void setupGeoFencePoints(final Location currentLocation) {

        mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
//        mLastLocation = currentLocation;

        if (currentLocation != null && isGeoFenceAdded == false)
        {
            if (mUpdateGeoFence) {
                if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
                    LocationServices.GeofencingApi.removeGeofences(mGoogleApiClient
                            , getGeofencePendingIntent()).setResultCallback(new ResultCallback<Status>() {
                        @Override
                        public void onResult(@NonNull Status status) {
                            if (status.isSuccess()) {
                                //if old geoFence's remove successfully then add new ones.
                                addGeoFences(currentLocation);
                            }
                        }
                    });
                }
            } else {
                addGeoFences(currentLocation);
            }
        }
        else if(isGeoFenceAdded && mRemoveAllGeoFence ){
            if (mGoogleApiClient != null && mGoogleApiClient.isConnected())
            {
                LocationServices.GeofencingApi.removeGeofences(mGoogleApiClient
                        , mGeofencePendingIntent).setResultCallback(new ResultCallback<Status>() {
                    @Override
                    public void onResult(@NonNull Status status) {
                        if (status.isSuccess()) {

                            mRemoveAllGeoFence = false;
                            isGeoFenceAdded = false;
                            //if old geoFence's remove successfully then do nothing.
                            stopLocationUpdate();

                            if (mGoogleApiClient != null && mGoogleApiClient.isConnected())
                                mGoogleApiClient.disconnect();
                        }
                    }
                });
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopLocationUpdate();

        if (mGoogleApiClient != null && mGoogleApiClient.isConnected())
            mGoogleApiClient.disconnect();
    }

    private void startLocationUpdates(final Context mContext) {

        if (ActivityCompat.checkSelfPermission(mContext,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(mContext,
                Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }

//        mLastLocation = FusedLocationApi.getLastLocation(mGoogleApiClient);

        PendingResult<Status> pendingResult = FusedLocationApi.requestLocationUpdates(
                mGoogleApiClient, mLocationRequest, this);
        pendingResult.setResultCallback(new ResultCallback<Status>() {
            @Override
            public void onResult(@NonNull Status status) {
                //update it's code too.
                if (status.isSuccess()) {
                    Toast.makeText(mContext, "location Update Started",
                            Toast.LENGTH_SHORT).show();
                } else if (status.hasResolution()) {
                    Toast.makeText(mContext, "Open intent to resolve",
                            Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    private void stopLocationUpdate() {
        //three types of constructor ..
        if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
            FusedLocationApi.removeLocationUpdates(
                    mGoogleApiClient, this);
        }
    }

    public void addGeoFences(Location currentLocation) {
        if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
            try {

                if (getGeofencingRequest(currentLocation) != null) {
                    LocationServices.GeofencingApi.addGeofences(
                            mGoogleApiClient,
                            // The GeofenceRequest object.
                            getGeofencingRequest(currentLocation),
                            // A pending intent that that is reused when calling removeGeofences(). This
                            // pending intent is used to generate an intent when a matched geofence
                            // transition is observed.
                            getGeofencePendingIntent()
                            //).await(TimeOut,TimeUnit.Miilisecponds);
                    ).setResultCallback(new ResultCallback<Status>() {
                        @Override
                        public void onResult(@NonNull Status status) {
                            if (status.isSuccess()) {
                                Toast.makeText(mContext, "Geo Fence Added", Toast.LENGTH_SHORT).show();

                                isGeoFenceAdded = true;
                                mRemoveAllGeoFence = false;
                                mUpdateGeoFence = false;

                                /// FIXME: 3/2/2017 I didn't have to draw it.
                                ///broadcastDrawGeoFenceOnMap();

                            } else {
                                String errorMessage = getErrorString(mContext, status.getStatusCode());
                                Toast.makeText(mContext, "Status Failed", Toast.LENGTH_SHORT).show();
                            }
                        }
                    }); // Result processed in onResult().
                }

            } catch (SecurityException securityException) {
                securityException.printStackTrace();
                // Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
                //logSecurityException(securityException);
            }
        }
    }

    private PendingIntent getGeofencePendingIntent() {
        if (mGeofencePendingIntent != null) {
            return mGeofencePendingIntent;
        }
        // Reuse the PendingIntent if we already have it.
        /// FIXME: 2/9/2017 Update the below class with a receiever..
        Intent intent = new Intent(mContext, GeofenceReceiver.class);///GeofenceTransitionsIntentService.class);
        // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling
        // addGeofences() and removeGeofences().
        /// FIXME: 3/1/2017 It must be reciever not IntentService
        mGeofencePendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        return mGeofencePendingIntent;
    }

    private GeofencingRequest getGeofencingRequest(Location mCurrentLocation) {

        /// FIXME: 2/13/2017 mLastLocation can be null because it will take time for the first time.
        /// this request should be called after first mLastLocation has been fetched..
        GeofencingRequest geofencingRequest = null;
        if (mCurrentLocation != null) {
            List<SimpleGeofence> simpleFenceList = SimpleGeofenceStore
                    .getInstance().getLatestGeoFences(mCurrentLocation);

            simpleFenceList.add(new SimpleGeofence("currentLocation",
                    mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude(),
                    100f, GEOFENCE_EXPIRATION_IN_MILLISECONDS,
                    Geofence.GEOFENCE_TRANSITION_EXIT));

            ListSharedPref.saveAnyTypeOfList(ListSharedPref.GEO_FENCE_LIST_KEY, simpleFenceList);

            GeofencingRequest.Builder geofencingRequestBuilder = new GeofencingRequest.Builder();
            geofencingRequestBuilder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);

            for (SimpleGeofence simpleGeofence : simpleFenceList)
                geofencingRequestBuilder.addGeofence(simpleGeofence.toGeofence());

            geofencingRequest = geofencingRequestBuilder.build();
        }
        // Return a GeofencingRequest.
        return geofencingRequest;
    }
}

GeofenceReceiver

public class GeofenceReceiver extends IntentService {
    public static final int NOTIFICATION_ID = 1;

    public GeofenceReceiver() {
        super("GeofenceReceiver");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        GeofencingEvent geoEvent = GeofencingEvent.fromIntent(intent);

        Location triggredLocation = geoEvent.getTriggeringLocation();

        if (geoEvent.hasError()) {
            Log.d(HomeActivity.TAG, "Error GeofenceReceiver.onHandleIntent");
        } else {
            Log.d(HomeActivity.TAG, "GeofenceReceiver : Transition -> "
                    + geoEvent.getGeofenceTransition());

            int transitionType = geoEvent.getGeofenceTransition();

            if (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER
                    || transitionType == Geofence.GEOFENCE_TRANSITION_DWELL
                    || transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
                List<Geofence> triggerList = geoEvent.getTriggeringGeofences();

                //if(triggerList.g)


                Type listType = new TypeToken<ArrayList<SimpleGeofence>>(){}.getType();
                List<SimpleGeofence> geoFenceList = GenericPref.readAnyTypeOfList(GenericPref.GEO_FENCE_LIST_KEY,listType);

                for (Geofence geofence : triggerList)
                {
                    /*SimpleGeofence sg = SimpleGeofenceStore.getInstance()
                            .getSimpleGeofences().get(geofence.getRequestId());*/

                    SimpleGeofence sg = null;
                    for(SimpleGeofence simpleGeofence : geoFenceList){
                        if(simpleGeofence.getId().equalsIgnoreCase(geofence.getRequestId())){
                            sg = simpleGeofence;
                            break;
                        }
                    }

                    String transitionName = "";
                    switch (transitionType) {
                        case Geofence.GEOFENCE_TRANSITION_DWELL:
                            transitionName = "dwell";
                            break;

                        case Geofence.GEOFENCE_TRANSITION_ENTER:
                            transitionName = "enter";

                            String date = DateFormat.format("yyyy-MM-dd hh:mm:ss",
                                    new Date()).toString();
                            EventDataSource eds = new EventDataSource(
                                    getApplicationContext());
                            eds.create(transitionName, date, geofence.getRequestId());
                            eds.close();

                            GeofenceNotification geofenceNotification = new GeofenceNotification(
                                    this);
                            if(sg != null){
                                geofenceNotification
                                        .displayNotification(sg, transitionType);
                            }
                            break;

                        case Geofence.GEOFENCE_TRANSITION_EXIT:
                            transitionName = "exit";
                            broadcastUpdateGeoFences();
                            //update your List
                            // Unregister all geoFences and reRegister it again
                            break;
                    }
                }
            }
        }
    }

    public void broadcastUpdateGeoFences() {
        //// FIXME: 3/2/2017 what if app is closed
        HomeActivity.geofencesAlreadyRegistered = false;
        MainActivity.isGeoFenceAdded = false;
        Intent intent = new Intent(Constants.RECEIVER_GEOFENCE);
        intent.putExtra("done", 1);
        sendBroadcast(intent);
    }
}
Zar E Ahmer
  • 33,936
  • 20
  • 234
  • 300