Today's development article is brought to you by one of our Placement Software Engineers, Sam. Sam has been working with us for a number of months now focusing on developing our Android app for Hello. Hello is part of our suite of smart office products that integrate with NetSuite. Specifically, Hello allows you to sign in and out of an office, client site, or another location, defined by client locations within your NetSuite system, allowing you to keep track of who is around, and stay compliant when it comes to fire safety registration etc.

For Sam, one of the main goals was to get Hello reminding the team to sign in and out of our building, via a notification based on your geographical location. Here is how Sam managed to create an app that meant we no longer had an excuse to forget to sign in, ever again!

What is Geofencing?

Well, it’s in the name; a geo(graphical) fence. Imagine it like a fenced off area. In technical terms it is: “the use of GPS technology to create a virtual geographic boundary, enabling software to trigger a response when a mobile device enters or leaves a particular area.” In simpler terms, it is a virtual perimeter for a real-world geographic area (Depicted in Figure 1).

 

Figure 1.  Shows a geofenced area with its three transition types: enter, dwell and exit.

 

Notifications

Any time the user enters/leaves the geofence we want a notification to appear on their mobile. An example of that is shown in Figure 2. For the purposes of this tutorial, we will not cover action buttons.

 

Figure 2.  A notification with icon, title, description and action buttons.

 

How to create a Geofence object

For this tutorial, we will use Java.

Let’s kick things off by creating a geofence. Firstly, create your geofencing class. Then, say, if you wanted to set up a geofence at the Google HQ you might do it like this:

private final static int GEOFENCE_RADIUS_IN_METERS = 300;
private final static long GEOFENCE_EXPIRATION_IN_MILLISECONDS = Geofence.NEVER_EXPIRE;
double Longitude = 37.422;
double Latitude = -122.084;

Geofence geofence = new Geofence.Builder()
        .setRequestId("Google HQ")
        .setCircularRegion(Latitude, Longitude, GEOFENCE_RADIUS_IN_METERS)
        .setExpirationDuration(GEOFENCE_EXPIRATION_IN_MILLISECONDS)
        .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
                Geofence.GEOFENCE_TRANSITION_EXIT |
                Geofence.GEOFENCE_TRANSITION_DWELL)
        .setLoiteringDelay(1)
        .build();

We can assign the radius of the geofence here: GEOFENCE_RADIUS_IN_METERS = 300;

(Note: Android does not recommend using a smaller radius than 100 meters as it cannot guarantee the accuracy.)

And the expiration time can be altered here: GEOFENCE_EXPIRATION_IN_MILLISECONDS = Geofence.NEVER_EXPIRE; (We have used data from a constants file).

The geofence has been created. Simple right?

However, in order to access the location APIs, we must add our geofence to a geofencing client. We can create a new instance of the GeofencingClient class like this in our constructor:

GeofencingClient mGeofencingClient = new GeofencingClient(context);

Now we can call mGeofencingClient.addGeofences() and two respective listeners, one for success and one for failure (of adding the geofence).

(Note: On single-user devices, there is a limit of 100 geofences per app. For multi-user devices, the limit is 100 geofences per app per device user.)

mGeofencingClient.addGeofences(getGeofencingRequest(), getGeofencePendingIntent())
        .addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                // do something
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                // do something
            }
        });

As you can see, we must create two methods, getGeofencingRequest() and getGeofencePendingIntent(), that are passed into mGeofencingClient.addGeofences() as parameters.

So getGeofencingRequest() will look something like this:

rivate GeofencingRequest getGeofencingRequest() {
        return new GeofencingRequest.Builder()
                .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER | GeofencingRequest.INITIAL_TRIGGER_DWELL)
                .addGeofences(mGeofenceList)
                .build();
}

mGeofenceList is just an ArrayList of type ‘Geofence’ (private ArrayList<Geofence> mGeofenceList) that I have added our ‘Google HQ’ geofence to.

Then getGeofencePendingIntent() like this:

Intent intent = new Intent(context, GeofenceTransitionsIntentService.class);
mGeofencePendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.
        FLAG_UPDATE_CURRENT);
return mGeofencePendingIntent;

Don’t forget to declare it.

private PendingIntent mGeofencePendingIntent;

Geofence Triggers

Now the Geofence is set up we are almost there! But now we want to be able to discern when and how the geofence has been triggered, either by entering, exiting or dwelling.

For this, we must create a class that extends ‘IntentService’. We have called ours ‘GeofenceTransitionsIntentService’. Not very catchy, I know.

So just implement the methods that IntentService requires (onCreate() and onHandleEvent()) then in the onHandleEvent method, we can write an ‘if’ statement to handle each of the transitions.

if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER) {
          // do something
} else if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
          // do something else
} else if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_DWELL) {
          // do something else again
}

You can separate or combine them however you like.

Bingo!

Geofencing; done.

Now, finally onto our notifications…

Notifications

We are going to need two classes: The NotificationBuilder and the NotificationReceiver.

Notification Builder class

Firstly, create a method in your activity (MainActivity in our case) named something like makeNotificationIntent(), then go back to NotificationBuilder and set the intent of the notification to the Activity you are using.

public static Intent makeNotificationIntent(Context geofenceService) {
    return new Intent(geofenceService, MainActivity.class);
}

and:

Intent notificationIntent = MainActivity.makeNotificationIntent(context);

Now we need a task stack builder that we can add the notification intent to.

TaskStackBuilder stackBuilder = TaskStackBuilder.create(context); stackBuilder.addParentStack(MainActivity.class); stackBuilder.addNextIntent(notificationIntent);

Get the pending intent from the stack builder and assign it to a variable of type ‘PendingIntent’ so we can use it as part of our notification setup.

PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

Next step is the creation of a notification manager that we can use to keep track of all of our notifications.

NotificationManager notificationMng = (NotificationManager) MainActivity.getContext().getSystemService(Context.NOTIFICATION_SERVICE);

Then we call the method to create the notification and then notify the notification manager.

Notification mNotification = createNotification(notificationPendingIntent, context);
notificationMng.notify(GEOFENCE_NOTIFICATION_ID_SIGNIN, mNotification);

Then we call the method to create the notification and then notify the notification manager.

Notification mNotification = createNotification(notificationPendingIntent, context);
notificationMng.notify(GEOFENCE_NOTIFICATION_ID_SIGNIN, mNotification);

(Note: for most of the context references, you’ll want the context to be that of your activity)

 

That method will look something like this:

NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context);
notificationBuilder
        .setColor(YourColor)
        .setSmallIcon(YourIcon)
        .setContentTitle(YourTitle)
        .setContentText(YourText)
        .setPriority(NotificationCompat.PRIORITY_MAX)
        .setContentIntent(notificationPendingIntent)
        .setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND | Notification.FLAG_AUTO_CANCEL)

(Note: This is deprecated in Android 8.0 Oreo (API 26).  For that you must use notification channels).

 

Notification Receiver class

This class must extend BroadcastReceiver and implement its method ‘onReceive()’. In our case we made use of a switch statement to decide what to do next, but you can do whatever you need.

That should be you set up to use geofencing with notifications in your android app. If you feel like we have missed anything or would like to ask any questions, feel free to use the comment section.

 

To stay in the loop for further news, guides, resources and more, sign up to "insight" our flagship weekly NetSuite and Business Software Newsletter, click here.

 
 

Comment