Create region monitor service
Description
The following code shows how to Create region monitor service.
Code revised from
Android Recipes:A Problem-Solution Approach
http://www.apress.com/9781430234135
ISBN13: 978-1-4302-3413-5
Example
Register service in manifest xml file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.androidrecipes.regionmonitor"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.androidrecipes.regionmonitor.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.androidrecipes.regionmonitor.RegionMonitorService" />
</application>
</manifest>
Main xml file
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/status"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<SeekBar
android:id="@+id/radius"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="1000"/>
<TextView
android:id="@+id/radius_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Set Geofence at My Location"
android:onClick="onSetGeofenceClick" />
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start Monitoring"
android:onClick="onStartMonitorClick" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Stop Monitoring"
android:onClick="onStopMonitorClick" />
</LinearLayout>
Main activity Java code
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationStatusCodes;
/* w w w. j ava 2s . c o m*/
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
public class MainActivity extends Activity implements
OnSeekBarChangeListener,
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener,
LocationClient.OnAddGeofencesResultListener,
LocationClient.OnRemoveGeofencesResultListener {
private static final String TAG = "RegionMonitorActivity";
private static final String FENCE_ID = "com.androidrecipes.FENCE";
private LocationClient mLocationClient;
private SeekBar mRadiusSlider;
private TextView mStatusText, mRadiusText;
private Geofence mCurrentFence;
private Intent mServiceIntent;
private PendingIntent mCallbackIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mStatusText = (TextView) findViewById(R.id.status);
mRadiusText = (TextView) findViewById(R.id.radius_text);
mRadiusSlider = (SeekBar) findViewById(R.id.radius);
mRadiusSlider.setOnSeekBarChangeListener(this);
updateRadiusDisplay();
switch (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this)) {
case ConnectionResult.SUCCESS:
//Do nothing, move on
break;
case ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED:
Toast.makeText(this,
"Geofencing service requires an update, please open Google Play.",
Toast.LENGTH_SHORT).show();
finish();
return;
default:
Toast.makeText(this,
"Geofencing service is not available on this device.",
Toast.LENGTH_SHORT).show();
finish();
return;
}
//Create a client for Google Services
mLocationClient = new LocationClient(this, this, this);
//Create an Intent to trigger our service
mServiceIntent = new Intent(this, RegionMonitorService.class);
//Create a PendingIntent for Google Services to use with callbacks
mCallbackIntent = PendingIntent.getService(this, 0, mServiceIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
}
@Override
protected void onResume() {
super.onResume();
//Connect to all services
if (!mLocationClient.isConnected()
&& !mLocationClient.isConnecting()) {
mLocationClient.connect();
}
}
@Override
protected void onPause() {
super.onPause();
//Disconnect when not in the foreground
mLocationClient.disconnect();
}
public void onSetGeofenceClick(View v) {
//Obtain the last location from services and radius
// from the UI
Location current = mLocationClient.getLastLocation();
int radius = mRadiusSlider.getProgress();
//Create a new Geofence using the Builder
Geofence.Builder builder = new Geofence.Builder();
mCurrentFence = builder
//Unique to this geofence
.setRequestId(FENCE_ID)
//Size and location
.setCircularRegion(
current.getLatitude(),
current.getLongitude(),
radius)
//Events both in and out of the fence
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER
| Geofence.GEOFENCE_TRANSITION_EXIT)
//Keep alive
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.build();
mStatusText.setText(String.format("Geofence set at %.3f, %.3f",
current.getLatitude(), current.getLongitude()) );
}
public void onStartMonitorClick(View v) {
if (mCurrentFence == null) {
Toast.makeText(this, "Geofence Not Yet Set",
Toast.LENGTH_SHORT).show();
return;
}
//Add the fence to start tracking, the PendingIntent will
// be triggered with new updates
ArrayList<Geofence> geofences = new ArrayList<Geofence>();
geofences.add(mCurrentFence);
mLocationClient.addGeofences(geofences, mCallbackIntent, this);
}
public void onStopMonitorClick(View v) {
//Remove to stop tracking
mLocationClient.removeGeofences(mCallbackIntent, this);
}
/** SeekBar Callbacks */
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
updateRadiusDisplay();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) { }
@Override
public void onStopTrackingTouch(SeekBar seekBar) { }
private void updateRadiusDisplay() {
mRadiusText.setText(mRadiusSlider.getProgress() + " meters");
}
/** Google Services Connection Callbacks */
@Override
public void onConnected(Bundle connectionHint) {
Log.v(TAG, "Google Services Connected");
}
@Override
public void onDisconnected() {
Log.w(TAG, "Google Services Disconnected");
}
@Override
public void onConnectionFailed(ConnectionResult result) {
Log.w(TAG, "Google Services Connection Failure");
}
/** LocationClient Callbacks */
/*
* Called when the asynchronous geofence add is complete.
* When this happens we start our monitoring service.
*/
@Override
public void onAddGeofencesResult(int statusCode,
String[] geofenceRequestIds) {
if (statusCode == LocationStatusCodes.SUCCESS) {
Toast.makeText(this, "Geofence Added Successfully", Toast.LENGTH_SHORT).show();
}
Intent startIntent = new Intent(mServiceIntent);
startIntent.setAction(RegionMonitorService.ACTION_INIT);
startService(mServiceIntent);
}
/*
* Called when the asynchronous geofence remove is complete.
* The version called depends on whether you requested the
* removal via PendingIntent or request Id.
* When this happens we stop our monitoring service.
*/
@Override
public void onRemoveGeofencesByPendingIntentResult(
int statusCode, PendingIntent pendingIntent) {
if (statusCode == LocationStatusCodes.SUCCESS) {
Toast.makeText(this, "Geofence Removed Successfully",
Toast.LENGTH_SHORT).show();
}
stopService(mServiceIntent);
}
@Override
public void onRemoveGeofencesByRequestIdsResult(
int statusCode, String[] geofenceRequestIds) {
if (statusCode == LocationStatusCodes.SUCCESS) {
Toast.makeText(this, "Geofence Removed Successfully",
Toast.LENGTH_SHORT).show();
}
stopService(mServiceIntent);
}
}
Service Java code
package com.java2s.myapplication3.app;
//w w w.j a v a2 s .co m
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.LocationClient;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
private static final String TAG = "RegionMonitorService";
private static final int NOTE_ID = 100;
//Unique action to identify start requests vs. events
public static final String ACTION_INIT =
"com.androidrecipes.regionmonitor.ACTION_INIT";
private NotificationManager mNoteManager;
@Override
public void onCreate() {
super.onCreate();
mNoteManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//Post a system notification when the service starts
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this);
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("Geofence Service");
builder.setContentText("Waiting for transition...");
builder.setOngoing(true);
Notification note = builder.build();
mNoteManager.notify(NOTE_ID, note);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//Nothing to do yet, just starting the service
if (ACTION_INIT.equals(intent.getAction())) {
//We don't care if this service dies unexpectedly
return START_NOT_STICKY;
}
if (LocationClient.hasError(intent)) {
//Log any errors
Log.w(TAG, "Error monitoring region: "
+ LocationClient.getErrorCode(intent));
} else {
//Update the ongoing notification from the new event
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this);
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setDefaults(Notification.DEFAULT_SOUND
| Notification.DEFAULT_LIGHTS);
builder.setOngoing(true);
int transitionType = LocationClient.getGeofenceTransition(intent);
//Check whether we entered or exited the region
if (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER) {
builder.setContentTitle("Geofence Transition");
builder.setContentText("Entered your Geofence");
} else if (transitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
builder.setContentTitle("Geofence Transition");
builder.setContentText("Exited your Geofence");
}
Notification note = builder.build();
mNoteManager.notify(NOTE_ID, note);
}
//We don't care if this service dies unexpectedly
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
//When the service dies, cancel our ongoing notification
mNoteManager.cancel(NOTE_ID);
}
/* We are not binding to this service */
@Override
public IBinder onBind(Intent intent) {
return null;
}
}