Geofence triggering issues in Android
up vote
0
down vote
favorite
I'm using android device's native Geofence service. Here are implementation details:
Tracked transition type: ENTER
Range: 500 meters (1640 feet)
Notification responsive time: 500ms
Added Geofence count: 15-20
Initial trigger (setInitialTrigger()): Not set
Location accuracy on device: High
Location permissions: FINE LOCATION and COARSE LOCATION
Location service on device: ON
Location permission to app: Yes
Android Oreo support: Yes (Used Broadcast receiver and JobIntentService)
Issues:
- On some device, same notification is triggering again and again when
user is moving withing same geofence. - On some device, some notifications are triggering some are not.
- On some device, no geofence in triggering at all.
Shall I move to third-party geofence services? If yes, could you please suggest any good service at this?
Creating goefence:
private const val NOTIFICATION_RESPONSIVENESS_TIME = 500
private const val GEOFENCE_RADIUS_IN_METERS = 500f
private const val GEOFENCE_PENDING_INTENT_REQUEST_CODE = 1
private fun createGeofences(context: Context, communityList: List<Community>) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return
}
//Adding geofence for all received communities
val geofenceList = communityList
.asSequence()
.filter { community -> isValidCommunityForGeofence(community) }
.map { community -> toGeofence(community) }
.toList()
val geofencingRequest = GeofencingRequest.Builder()
.addGeofences(geofenceList)
.build()
val pendingIntent = getGeofencePendingIntent(context)
val geofencingClient: GeofencingClient = LocationServices.getGeofencingClient(context)
geofencingClient.addGeofences(geofencingRequest, pendingIntent)
.addOnCompleteListener(GeofenceAddRemoveListener(true))
}
private fun toGeofence(community: Community): Geofence {
return Geofence.Builder()
.setRequestId(community.bdxCommunityId.toString())//unique ID for geofence
.setCircularRegion(community.latitude, community.longitude, GEOFENCE_RADIUS_IN_METERS)
.setNotificationResponsiveness(NOTIFICATION_RESPONSIVENESS_TIME)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setLoiteringDelay(0)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
.build()
}
private fun getGeofencePendingIntent(context: Context): PendingIntent {
val intent = Intent(context, GeofenceBroadcastReceiver::class.java)
return PendingIntent.getBroadcast(context, GEOFENCE_PENDING_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
private fun isValidCommunityForGeofence(community: Community): Boolean {
return community.latitude != null && community.longitude != null && community.latitude != 0.0
&& community.longitude != 0.0 && !TextUtils.isEmpty(community.name)
}
Manifest file:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.location.network" />
<uses-feature android:name="android.hardware.location.gps" />
<receiver
android:name=".misc.geofence.GeofenceBroadcastReceiver"
android:enabled="true"
android:exported="true" />
<service
android:name=".misc.geofence.GeofenceTransitionsJobIntentService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
Broadcast receiver:
class GeofenceBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// Enqueues a JobIntentService passing the context and intent as parameters
GeofenceTransitionsJobIntentService.enqueueWork(context, intent)
}
}
JobIntentService:
class GeofenceTransitionsJobIntentService : JobIntentService() {
companion object {
fun enqueueWork(context: Context, intent: Intent) {
JobIntentService.enqueueWork(context, GeofenceTransitionsJobIntentService::class.java, JobServiceID.GEOFENCE_JOB_ID, intent)
}
}
/**
* Handles incoming intents.
*
* @param intent sent by Location Services. This Intent is provided to Location Services (inside a PendingIntent)
* when @GeofenceInteractor#refreshGeofences() is called.
*/
override fun onHandleWork(intent: Intent) {
val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent.hasError()) {
val errorMessage = GeofenceErrorMessages.getErrorString(geofencingEvent.errorCode)
Logger.e(this, errorMessage)
return
}
val geofenceTransition = geofencingEvent.geofenceTransition
val userCommunityList = GeofenceInteractor.getUserCommunityList(this)
// Get the geofences that were triggered. A single event can trigger multiple geofences.
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER) {
val triggeringGeofences = geofencingEvent.triggeringGeofences
//Showing notification for each geofence which triggered ENTER transition.
for (geofence in triggeringGeofences) {
val community = userCommunityList.asSequence().filter { community -> community.bdxCommunityId == geofence.requestId.toInt() }.firstOrNull()
if (community != null) {
val transitionMessage = String.format(resources.getString(R.string.community_geofence_transition_entered), community.name)
sendGeofenceNotification(transitionMessage, community)
}
Logger.d(this, "Geofene triggered. Transition: " + geofenceTransition + " Community:" + community?.name)
}
} else {
Logger.e(this, getString(R.string.geofence_transition_invalid_type, geofenceTransition))
}
}
private fun sendGeofenceNotification(contentText: String, community: Community) {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?
?: return
val notificationBuilder = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
NotificationCompat.Builder(this)
} else {
val notificationChannel = NotificationUtil.getOrCreateGeofenceNotificationChannel(this, notificationManager)!!
NotificationCompat.Builder(this, notificationChannel.id)
}
val nextNotificationId = NotificationUtil.getNextNotificationId(this)
val viewCommunityPendingIntent = getViewCommunityPendingIntent(nextNotificationId, community)
val mapNavigationPendingIntent = getGeofenceMapNavigationPendingIntent(nextNotificationId, community)
notificationBuilder.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))
.setContentTitle(community.name)
.setContentText(contentText)
.setContentIntent(viewCommunityPendingIntent)
.setAutoCancel(true)
.setGroup(NotificationUtil.GEOFENCE_GROUP)
.addAction(0, getString(R.string.navigate_to_community), mapNavigationPendingIntent)
.addAction(0, getString(R.string.view), viewCommunityPendingIntent)
notificationManager.notify(nextNotificationId, notificationBuilder.build())
}
private fun getViewCommunityPendingIntent(notificationId: Int, community: Community): PendingIntent? {
val notificationBundle = Bundle()
notificationBundle.putParcelable(Constants.COMMUNITY, community)
notificationBundle.putInt(Constants.NOTIFICATION_ID, notificationId)
val notificationIntent = Intent(applicationContext, SplashActivity::class.java)
notificationIntent.putExtras(notificationBundle)
val stackBuilder = TaskStackBuilder.create(this)
stackBuilder.addParentStack(SplashActivity::class.java)
stackBuilder.addNextIntent(notificationIntent)
return stackBuilder.getPendingIntent(notificationId, PendingIntent.FLAG_UPDATE_CURRENT)
}
private fun getGeofenceMapNavigationPendingIntent(notificationId: Int, community: Community): PendingIntent? {
val notificationBundle = Bundle()
notificationBundle.putParcelable(Constants.COMMUNITY, community)
notificationBundle.putInt(Constants.NOTIFICATION_ID, notificationId)
val geofenceMapNavigationIntent = Intent(this, GeofenceMapNavigationActivity::class.java)
geofenceMapNavigationIntent.putExtras(notificationBundle)
val mapNavigationStackBuilder = TaskStackBuilder.create(this)
mapNavigationStackBuilder.addParentStack(SplashActivity::class.java)
mapNavigationStackBuilder.addNextIntent(geofenceMapNavigationIntent)
return mapNavigationStackBuilder.getPendingIntent(notificationId, PendingIntent.FLAG_UPDATE_CURRENT)
}
}
android android-geofence
add a comment |
up vote
0
down vote
favorite
I'm using android device's native Geofence service. Here are implementation details:
Tracked transition type: ENTER
Range: 500 meters (1640 feet)
Notification responsive time: 500ms
Added Geofence count: 15-20
Initial trigger (setInitialTrigger()): Not set
Location accuracy on device: High
Location permissions: FINE LOCATION and COARSE LOCATION
Location service on device: ON
Location permission to app: Yes
Android Oreo support: Yes (Used Broadcast receiver and JobIntentService)
Issues:
- On some device, same notification is triggering again and again when
user is moving withing same geofence. - On some device, some notifications are triggering some are not.
- On some device, no geofence in triggering at all.
Shall I move to third-party geofence services? If yes, could you please suggest any good service at this?
Creating goefence:
private const val NOTIFICATION_RESPONSIVENESS_TIME = 500
private const val GEOFENCE_RADIUS_IN_METERS = 500f
private const val GEOFENCE_PENDING_INTENT_REQUEST_CODE = 1
private fun createGeofences(context: Context, communityList: List<Community>) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return
}
//Adding geofence for all received communities
val geofenceList = communityList
.asSequence()
.filter { community -> isValidCommunityForGeofence(community) }
.map { community -> toGeofence(community) }
.toList()
val geofencingRequest = GeofencingRequest.Builder()
.addGeofences(geofenceList)
.build()
val pendingIntent = getGeofencePendingIntent(context)
val geofencingClient: GeofencingClient = LocationServices.getGeofencingClient(context)
geofencingClient.addGeofences(geofencingRequest, pendingIntent)
.addOnCompleteListener(GeofenceAddRemoveListener(true))
}
private fun toGeofence(community: Community): Geofence {
return Geofence.Builder()
.setRequestId(community.bdxCommunityId.toString())//unique ID for geofence
.setCircularRegion(community.latitude, community.longitude, GEOFENCE_RADIUS_IN_METERS)
.setNotificationResponsiveness(NOTIFICATION_RESPONSIVENESS_TIME)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setLoiteringDelay(0)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
.build()
}
private fun getGeofencePendingIntent(context: Context): PendingIntent {
val intent = Intent(context, GeofenceBroadcastReceiver::class.java)
return PendingIntent.getBroadcast(context, GEOFENCE_PENDING_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
private fun isValidCommunityForGeofence(community: Community): Boolean {
return community.latitude != null && community.longitude != null && community.latitude != 0.0
&& community.longitude != 0.0 && !TextUtils.isEmpty(community.name)
}
Manifest file:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.location.network" />
<uses-feature android:name="android.hardware.location.gps" />
<receiver
android:name=".misc.geofence.GeofenceBroadcastReceiver"
android:enabled="true"
android:exported="true" />
<service
android:name=".misc.geofence.GeofenceTransitionsJobIntentService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
Broadcast receiver:
class GeofenceBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// Enqueues a JobIntentService passing the context and intent as parameters
GeofenceTransitionsJobIntentService.enqueueWork(context, intent)
}
}
JobIntentService:
class GeofenceTransitionsJobIntentService : JobIntentService() {
companion object {
fun enqueueWork(context: Context, intent: Intent) {
JobIntentService.enqueueWork(context, GeofenceTransitionsJobIntentService::class.java, JobServiceID.GEOFENCE_JOB_ID, intent)
}
}
/**
* Handles incoming intents.
*
* @param intent sent by Location Services. This Intent is provided to Location Services (inside a PendingIntent)
* when @GeofenceInteractor#refreshGeofences() is called.
*/
override fun onHandleWork(intent: Intent) {
val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent.hasError()) {
val errorMessage = GeofenceErrorMessages.getErrorString(geofencingEvent.errorCode)
Logger.e(this, errorMessage)
return
}
val geofenceTransition = geofencingEvent.geofenceTransition
val userCommunityList = GeofenceInteractor.getUserCommunityList(this)
// Get the geofences that were triggered. A single event can trigger multiple geofences.
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER) {
val triggeringGeofences = geofencingEvent.triggeringGeofences
//Showing notification for each geofence which triggered ENTER transition.
for (geofence in triggeringGeofences) {
val community = userCommunityList.asSequence().filter { community -> community.bdxCommunityId == geofence.requestId.toInt() }.firstOrNull()
if (community != null) {
val transitionMessage = String.format(resources.getString(R.string.community_geofence_transition_entered), community.name)
sendGeofenceNotification(transitionMessage, community)
}
Logger.d(this, "Geofene triggered. Transition: " + geofenceTransition + " Community:" + community?.name)
}
} else {
Logger.e(this, getString(R.string.geofence_transition_invalid_type, geofenceTransition))
}
}
private fun sendGeofenceNotification(contentText: String, community: Community) {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?
?: return
val notificationBuilder = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
NotificationCompat.Builder(this)
} else {
val notificationChannel = NotificationUtil.getOrCreateGeofenceNotificationChannel(this, notificationManager)!!
NotificationCompat.Builder(this, notificationChannel.id)
}
val nextNotificationId = NotificationUtil.getNextNotificationId(this)
val viewCommunityPendingIntent = getViewCommunityPendingIntent(nextNotificationId, community)
val mapNavigationPendingIntent = getGeofenceMapNavigationPendingIntent(nextNotificationId, community)
notificationBuilder.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))
.setContentTitle(community.name)
.setContentText(contentText)
.setContentIntent(viewCommunityPendingIntent)
.setAutoCancel(true)
.setGroup(NotificationUtil.GEOFENCE_GROUP)
.addAction(0, getString(R.string.navigate_to_community), mapNavigationPendingIntent)
.addAction(0, getString(R.string.view), viewCommunityPendingIntent)
notificationManager.notify(nextNotificationId, notificationBuilder.build())
}
private fun getViewCommunityPendingIntent(notificationId: Int, community: Community): PendingIntent? {
val notificationBundle = Bundle()
notificationBundle.putParcelable(Constants.COMMUNITY, community)
notificationBundle.putInt(Constants.NOTIFICATION_ID, notificationId)
val notificationIntent = Intent(applicationContext, SplashActivity::class.java)
notificationIntent.putExtras(notificationBundle)
val stackBuilder = TaskStackBuilder.create(this)
stackBuilder.addParentStack(SplashActivity::class.java)
stackBuilder.addNextIntent(notificationIntent)
return stackBuilder.getPendingIntent(notificationId, PendingIntent.FLAG_UPDATE_CURRENT)
}
private fun getGeofenceMapNavigationPendingIntent(notificationId: Int, community: Community): PendingIntent? {
val notificationBundle = Bundle()
notificationBundle.putParcelable(Constants.COMMUNITY, community)
notificationBundle.putInt(Constants.NOTIFICATION_ID, notificationId)
val geofenceMapNavigationIntent = Intent(this, GeofenceMapNavigationActivity::class.java)
geofenceMapNavigationIntent.putExtras(notificationBundle)
val mapNavigationStackBuilder = TaskStackBuilder.create(this)
mapNavigationStackBuilder.addParentStack(SplashActivity::class.java)
mapNavigationStackBuilder.addNextIntent(geofenceMapNavigationIntent)
return mapNavigationStackBuilder.getPendingIntent(notificationId, PendingIntent.FLAG_UPDATE_CURRENT)
}
}
android android-geofence
please post the code
– Vikash Bijarniya
Nov 21 at 5:47
@VikashBijarniya Added source code.
– Rahul Rastogi
Nov 21 at 6:00
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I'm using android device's native Geofence service. Here are implementation details:
Tracked transition type: ENTER
Range: 500 meters (1640 feet)
Notification responsive time: 500ms
Added Geofence count: 15-20
Initial trigger (setInitialTrigger()): Not set
Location accuracy on device: High
Location permissions: FINE LOCATION and COARSE LOCATION
Location service on device: ON
Location permission to app: Yes
Android Oreo support: Yes (Used Broadcast receiver and JobIntentService)
Issues:
- On some device, same notification is triggering again and again when
user is moving withing same geofence. - On some device, some notifications are triggering some are not.
- On some device, no geofence in triggering at all.
Shall I move to third-party geofence services? If yes, could you please suggest any good service at this?
Creating goefence:
private const val NOTIFICATION_RESPONSIVENESS_TIME = 500
private const val GEOFENCE_RADIUS_IN_METERS = 500f
private const val GEOFENCE_PENDING_INTENT_REQUEST_CODE = 1
private fun createGeofences(context: Context, communityList: List<Community>) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return
}
//Adding geofence for all received communities
val geofenceList = communityList
.asSequence()
.filter { community -> isValidCommunityForGeofence(community) }
.map { community -> toGeofence(community) }
.toList()
val geofencingRequest = GeofencingRequest.Builder()
.addGeofences(geofenceList)
.build()
val pendingIntent = getGeofencePendingIntent(context)
val geofencingClient: GeofencingClient = LocationServices.getGeofencingClient(context)
geofencingClient.addGeofences(geofencingRequest, pendingIntent)
.addOnCompleteListener(GeofenceAddRemoveListener(true))
}
private fun toGeofence(community: Community): Geofence {
return Geofence.Builder()
.setRequestId(community.bdxCommunityId.toString())//unique ID for geofence
.setCircularRegion(community.latitude, community.longitude, GEOFENCE_RADIUS_IN_METERS)
.setNotificationResponsiveness(NOTIFICATION_RESPONSIVENESS_TIME)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setLoiteringDelay(0)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
.build()
}
private fun getGeofencePendingIntent(context: Context): PendingIntent {
val intent = Intent(context, GeofenceBroadcastReceiver::class.java)
return PendingIntent.getBroadcast(context, GEOFENCE_PENDING_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
private fun isValidCommunityForGeofence(community: Community): Boolean {
return community.latitude != null && community.longitude != null && community.latitude != 0.0
&& community.longitude != 0.0 && !TextUtils.isEmpty(community.name)
}
Manifest file:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.location.network" />
<uses-feature android:name="android.hardware.location.gps" />
<receiver
android:name=".misc.geofence.GeofenceBroadcastReceiver"
android:enabled="true"
android:exported="true" />
<service
android:name=".misc.geofence.GeofenceTransitionsJobIntentService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
Broadcast receiver:
class GeofenceBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// Enqueues a JobIntentService passing the context and intent as parameters
GeofenceTransitionsJobIntentService.enqueueWork(context, intent)
}
}
JobIntentService:
class GeofenceTransitionsJobIntentService : JobIntentService() {
companion object {
fun enqueueWork(context: Context, intent: Intent) {
JobIntentService.enqueueWork(context, GeofenceTransitionsJobIntentService::class.java, JobServiceID.GEOFENCE_JOB_ID, intent)
}
}
/**
* Handles incoming intents.
*
* @param intent sent by Location Services. This Intent is provided to Location Services (inside a PendingIntent)
* when @GeofenceInteractor#refreshGeofences() is called.
*/
override fun onHandleWork(intent: Intent) {
val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent.hasError()) {
val errorMessage = GeofenceErrorMessages.getErrorString(geofencingEvent.errorCode)
Logger.e(this, errorMessage)
return
}
val geofenceTransition = geofencingEvent.geofenceTransition
val userCommunityList = GeofenceInteractor.getUserCommunityList(this)
// Get the geofences that were triggered. A single event can trigger multiple geofences.
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER) {
val triggeringGeofences = geofencingEvent.triggeringGeofences
//Showing notification for each geofence which triggered ENTER transition.
for (geofence in triggeringGeofences) {
val community = userCommunityList.asSequence().filter { community -> community.bdxCommunityId == geofence.requestId.toInt() }.firstOrNull()
if (community != null) {
val transitionMessage = String.format(resources.getString(R.string.community_geofence_transition_entered), community.name)
sendGeofenceNotification(transitionMessage, community)
}
Logger.d(this, "Geofene triggered. Transition: " + geofenceTransition + " Community:" + community?.name)
}
} else {
Logger.e(this, getString(R.string.geofence_transition_invalid_type, geofenceTransition))
}
}
private fun sendGeofenceNotification(contentText: String, community: Community) {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?
?: return
val notificationBuilder = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
NotificationCompat.Builder(this)
} else {
val notificationChannel = NotificationUtil.getOrCreateGeofenceNotificationChannel(this, notificationManager)!!
NotificationCompat.Builder(this, notificationChannel.id)
}
val nextNotificationId = NotificationUtil.getNextNotificationId(this)
val viewCommunityPendingIntent = getViewCommunityPendingIntent(nextNotificationId, community)
val mapNavigationPendingIntent = getGeofenceMapNavigationPendingIntent(nextNotificationId, community)
notificationBuilder.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))
.setContentTitle(community.name)
.setContentText(contentText)
.setContentIntent(viewCommunityPendingIntent)
.setAutoCancel(true)
.setGroup(NotificationUtil.GEOFENCE_GROUP)
.addAction(0, getString(R.string.navigate_to_community), mapNavigationPendingIntent)
.addAction(0, getString(R.string.view), viewCommunityPendingIntent)
notificationManager.notify(nextNotificationId, notificationBuilder.build())
}
private fun getViewCommunityPendingIntent(notificationId: Int, community: Community): PendingIntent? {
val notificationBundle = Bundle()
notificationBundle.putParcelable(Constants.COMMUNITY, community)
notificationBundle.putInt(Constants.NOTIFICATION_ID, notificationId)
val notificationIntent = Intent(applicationContext, SplashActivity::class.java)
notificationIntent.putExtras(notificationBundle)
val stackBuilder = TaskStackBuilder.create(this)
stackBuilder.addParentStack(SplashActivity::class.java)
stackBuilder.addNextIntent(notificationIntent)
return stackBuilder.getPendingIntent(notificationId, PendingIntent.FLAG_UPDATE_CURRENT)
}
private fun getGeofenceMapNavigationPendingIntent(notificationId: Int, community: Community): PendingIntent? {
val notificationBundle = Bundle()
notificationBundle.putParcelable(Constants.COMMUNITY, community)
notificationBundle.putInt(Constants.NOTIFICATION_ID, notificationId)
val geofenceMapNavigationIntent = Intent(this, GeofenceMapNavigationActivity::class.java)
geofenceMapNavigationIntent.putExtras(notificationBundle)
val mapNavigationStackBuilder = TaskStackBuilder.create(this)
mapNavigationStackBuilder.addParentStack(SplashActivity::class.java)
mapNavigationStackBuilder.addNextIntent(geofenceMapNavigationIntent)
return mapNavigationStackBuilder.getPendingIntent(notificationId, PendingIntent.FLAG_UPDATE_CURRENT)
}
}
android android-geofence
I'm using android device's native Geofence service. Here are implementation details:
Tracked transition type: ENTER
Range: 500 meters (1640 feet)
Notification responsive time: 500ms
Added Geofence count: 15-20
Initial trigger (setInitialTrigger()): Not set
Location accuracy on device: High
Location permissions: FINE LOCATION and COARSE LOCATION
Location service on device: ON
Location permission to app: Yes
Android Oreo support: Yes (Used Broadcast receiver and JobIntentService)
Issues:
- On some device, same notification is triggering again and again when
user is moving withing same geofence. - On some device, some notifications are triggering some are not.
- On some device, no geofence in triggering at all.
Shall I move to third-party geofence services? If yes, could you please suggest any good service at this?
Creating goefence:
private const val NOTIFICATION_RESPONSIVENESS_TIME = 500
private const val GEOFENCE_RADIUS_IN_METERS = 500f
private const val GEOFENCE_PENDING_INTENT_REQUEST_CODE = 1
private fun createGeofences(context: Context, communityList: List<Community>) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return
}
//Adding geofence for all received communities
val geofenceList = communityList
.asSequence()
.filter { community -> isValidCommunityForGeofence(community) }
.map { community -> toGeofence(community) }
.toList()
val geofencingRequest = GeofencingRequest.Builder()
.addGeofences(geofenceList)
.build()
val pendingIntent = getGeofencePendingIntent(context)
val geofencingClient: GeofencingClient = LocationServices.getGeofencingClient(context)
geofencingClient.addGeofences(geofencingRequest, pendingIntent)
.addOnCompleteListener(GeofenceAddRemoveListener(true))
}
private fun toGeofence(community: Community): Geofence {
return Geofence.Builder()
.setRequestId(community.bdxCommunityId.toString())//unique ID for geofence
.setCircularRegion(community.latitude, community.longitude, GEOFENCE_RADIUS_IN_METERS)
.setNotificationResponsiveness(NOTIFICATION_RESPONSIVENESS_TIME)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setLoiteringDelay(0)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
.build()
}
private fun getGeofencePendingIntent(context: Context): PendingIntent {
val intent = Intent(context, GeofenceBroadcastReceiver::class.java)
return PendingIntent.getBroadcast(context, GEOFENCE_PENDING_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
private fun isValidCommunityForGeofence(community: Community): Boolean {
return community.latitude != null && community.longitude != null && community.latitude != 0.0
&& community.longitude != 0.0 && !TextUtils.isEmpty(community.name)
}
Manifest file:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.location.network" />
<uses-feature android:name="android.hardware.location.gps" />
<receiver
android:name=".misc.geofence.GeofenceBroadcastReceiver"
android:enabled="true"
android:exported="true" />
<service
android:name=".misc.geofence.GeofenceTransitionsJobIntentService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
Broadcast receiver:
class GeofenceBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// Enqueues a JobIntentService passing the context and intent as parameters
GeofenceTransitionsJobIntentService.enqueueWork(context, intent)
}
}
JobIntentService:
class GeofenceTransitionsJobIntentService : JobIntentService() {
companion object {
fun enqueueWork(context: Context, intent: Intent) {
JobIntentService.enqueueWork(context, GeofenceTransitionsJobIntentService::class.java, JobServiceID.GEOFENCE_JOB_ID, intent)
}
}
/**
* Handles incoming intents.
*
* @param intent sent by Location Services. This Intent is provided to Location Services (inside a PendingIntent)
* when @GeofenceInteractor#refreshGeofences() is called.
*/
override fun onHandleWork(intent: Intent) {
val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent.hasError()) {
val errorMessage = GeofenceErrorMessages.getErrorString(geofencingEvent.errorCode)
Logger.e(this, errorMessage)
return
}
val geofenceTransition = geofencingEvent.geofenceTransition
val userCommunityList = GeofenceInteractor.getUserCommunityList(this)
// Get the geofences that were triggered. A single event can trigger multiple geofences.
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER) {
val triggeringGeofences = geofencingEvent.triggeringGeofences
//Showing notification for each geofence which triggered ENTER transition.
for (geofence in triggeringGeofences) {
val community = userCommunityList.asSequence().filter { community -> community.bdxCommunityId == geofence.requestId.toInt() }.firstOrNull()
if (community != null) {
val transitionMessage = String.format(resources.getString(R.string.community_geofence_transition_entered), community.name)
sendGeofenceNotification(transitionMessage, community)
}
Logger.d(this, "Geofene triggered. Transition: " + geofenceTransition + " Community:" + community?.name)
}
} else {
Logger.e(this, getString(R.string.geofence_transition_invalid_type, geofenceTransition))
}
}
private fun sendGeofenceNotification(contentText: String, community: Community) {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?
?: return
val notificationBuilder = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
NotificationCompat.Builder(this)
} else {
val notificationChannel = NotificationUtil.getOrCreateGeofenceNotificationChannel(this, notificationManager)!!
NotificationCompat.Builder(this, notificationChannel.id)
}
val nextNotificationId = NotificationUtil.getNextNotificationId(this)
val viewCommunityPendingIntent = getViewCommunityPendingIntent(nextNotificationId, community)
val mapNavigationPendingIntent = getGeofenceMapNavigationPendingIntent(nextNotificationId, community)
notificationBuilder.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))
.setContentTitle(community.name)
.setContentText(contentText)
.setContentIntent(viewCommunityPendingIntent)
.setAutoCancel(true)
.setGroup(NotificationUtil.GEOFENCE_GROUP)
.addAction(0, getString(R.string.navigate_to_community), mapNavigationPendingIntent)
.addAction(0, getString(R.string.view), viewCommunityPendingIntent)
notificationManager.notify(nextNotificationId, notificationBuilder.build())
}
private fun getViewCommunityPendingIntent(notificationId: Int, community: Community): PendingIntent? {
val notificationBundle = Bundle()
notificationBundle.putParcelable(Constants.COMMUNITY, community)
notificationBundle.putInt(Constants.NOTIFICATION_ID, notificationId)
val notificationIntent = Intent(applicationContext, SplashActivity::class.java)
notificationIntent.putExtras(notificationBundle)
val stackBuilder = TaskStackBuilder.create(this)
stackBuilder.addParentStack(SplashActivity::class.java)
stackBuilder.addNextIntent(notificationIntent)
return stackBuilder.getPendingIntent(notificationId, PendingIntent.FLAG_UPDATE_CURRENT)
}
private fun getGeofenceMapNavigationPendingIntent(notificationId: Int, community: Community): PendingIntent? {
val notificationBundle = Bundle()
notificationBundle.putParcelable(Constants.COMMUNITY, community)
notificationBundle.putInt(Constants.NOTIFICATION_ID, notificationId)
val geofenceMapNavigationIntent = Intent(this, GeofenceMapNavigationActivity::class.java)
geofenceMapNavigationIntent.putExtras(notificationBundle)
val mapNavigationStackBuilder = TaskStackBuilder.create(this)
mapNavigationStackBuilder.addParentStack(SplashActivity::class.java)
mapNavigationStackBuilder.addNextIntent(geofenceMapNavigationIntent)
return mapNavigationStackBuilder.getPendingIntent(notificationId, PendingIntent.FLAG_UPDATE_CURRENT)
}
}
android android-geofence
android android-geofence
edited Nov 21 at 5:59
asked Nov 21 at 5:38
Rahul Rastogi
68521031
68521031
please post the code
– Vikash Bijarniya
Nov 21 at 5:47
@VikashBijarniya Added source code.
– Rahul Rastogi
Nov 21 at 6:00
add a comment |
please post the code
– Vikash Bijarniya
Nov 21 at 5:47
@VikashBijarniya Added source code.
– Rahul Rastogi
Nov 21 at 6:00
please post the code
– Vikash Bijarniya
Nov 21 at 5:47
please post the code
– Vikash Bijarniya
Nov 21 at 5:47
@VikashBijarniya Added source code.
– Rahul Rastogi
Nov 21 at 6:00
@VikashBijarniya Added source code.
– Rahul Rastogi
Nov 21 at 6:00
add a comment |
1 Answer
1
active
oldest
votes
up vote
0
down vote
Let me show you what i have done for a similar task. Below code has been used to achieve geofencing.
class LocationService : Service(), GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
var mLocationManager: LocationManager? = null
var googleApiClient: GoogleApiClient? = null
var pendingIntent: PendingIntent? = null
var geofencingRequest: GeofencingRequest? = null
var mGeofenceList: ArrayList<Geofence>? = null
private inner class LocationListener(provider: String) : android.location.LocationListener {
private var mLastLocation: Location = Location(provider)
override fun onLocationChanged(location: Location) {
mLastLocation.set(location)
}
override fun onProviderDisabled(provider: String) {}
override fun onProviderEnabled(provider: String) {}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
}
internal var mLocationListeners = arrayOf<android.location.LocationListener>(LocationListener(LocationManager.GPS_PROVIDER), LocationListener(LocationManager.NETWORK_PROVIDER))
override fun onBind(arg0: Intent): IBinder? {
return null
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
mGeofenceList = ArrayList()
populateGeofenceList()
super.onStartCommand(intent, flags, startId)
return Service.START_STICKY
}
override fun onCreate() {
initializeLocationManager()
try {
mLocationManager!!.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, Constant.LOCATION_INTERVAL.toLong(), Constant.LOCATION_DISTANCE, mLocationListeners[1])
} catch (ex: java.lang.SecurityException) {
ex.printStackTrace()
} catch (ex: IllegalArgumentException) {
ex.printStackTrace()
}
try {
mLocationManager!!.requestLocationUpdates(
LocationManager.GPS_PROVIDER, Constant.LOCATION_INTERVAL.toLong(), Constant.LOCATION_DISTANCE,
mLocationListeners[0])
} catch (ex: java.lang.SecurityException) {
ex.printStackTrace()
} catch (ex: IllegalArgumentException) {
ex.printStackTrace()
}
}
override fun onDestroy() {
super.onDestroy()
if (mLocationManager != null) {
for (i in mLocationListeners.indices) {
try {
mLocationManager!!.removeUpdates(mLocationListeners[i])
} catch (ex: Exception) {
ex.printStackTrace()
}
}
}
}
private fun initializeLocationManager() {
googleApiClient = GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build()
googleApiClient!!.connect()
if (mLocationManager == null) {
mLocationManager = applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
}
}
private fun startLocationMonitor() {
val locationRequest = LocationRequest.create()
.setInterval(Constant.LOCATION_INTERVAL.toLong())
.setFastestInterval(Constant.LOCATION_INTERVAL.toLong())
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
try {
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, object : com.google.android.gms.location.LocationListener {
override fun onLocationChanged(location: Location) {
DashBoardActivity.latitude = location.latitude
DashBoardActivity.longitude = location.longitude
if (BuildConfig.DEBUG) {
Log.e("LocationChanged:", location.latitude.toString() + " ," + location.longitude)
}
}
})
} catch (e: SecurityException) {
e.printStackTrace()
}
}
private fun startGeofencing() {
pendingIntent = getGeofencePendingIntent()
geofencingRequest = GeofencingRequest.Builder()
.setInitialTrigger(Geofence.GEOFENCE_TRANSITION_ENTER)
.addGeofences(mGeofenceList)
.build()
if (googleApiClient?.isConnected!!) {
try {
LocationServices.GeofencingApi.addGeofences(googleApiClient, geofencingRequest, pendingIntent).setResultCallback(object : ResultCallback<Status> {
override fun onResult(status: Status) {
}
})
} catch (e: SecurityException) {
e.printStackTrace()
}
}
}
private fun populateGeofenceList() {
for (entry in Constant.AREA_LANDMARKS.entries) { // Replace with your Location List
mGeofenceList?.add(Geofence.Builder()
.setRequestId(entry.key)
.setCircularRegion(entry.value.latitude, entry.value.longitude, Constant.GEOFENCE_RADIUS_IN_METERS)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setNotificationResponsiveness(1000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT)
.build())
}
}
private fun getGeofencePendingIntent(): PendingIntent? {
if (pendingIntent != null) {
return pendingIntent
}
val intent = Intent(this, GeofenceRegistrationService::class.java)
pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
return pendingIntent
}
override fun onConnected(bundle: Bundle?) {
startGeofencing()
startLocationMonitor()
}
override fun onConnectionSuspended(i: Int) {}
override fun onConnectionFailed(connectionResult: ConnectionResult) {}
}
For getting the geofence events, i have used below code:
class GeofenceRegistrationService : IntentService("GeoIntentService") {
val TAG = "GeoIntentService"
var mGeofencList: ArrayList<Geofence>? = null
override fun onHandleIntent(intent: Intent?) {
mGeofencList = ArrayList()
val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent.hasError()) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "Error" + geofencingEvent.errorCode)
}
} else {
try {
val transaction = geofencingEvent.geofenceTransition
val geofences = geofencingEvent.triggeringGeofences
for (i in 0 until geofences.size) {
mGeofencList?.add(geofences[i])
}
if (transaction == Geofence.GEOFENCE_TRANSITION_ENTER) {
sendBroadCast(true)
if (BuildConfig.DEBUG) {
Log.d(TAG, "You are inside Geofenced area")
}
}
if (transaction == Geofence.GEOFENCE_TRANSITION_EXIT) {
sendBroadCast(false)
if (BuildConfig.DEBUG) {
Log.d(TAG, "You are outside Geofenced area")
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
private fun sendBroadCast(isInside: Boolean) {
val broadCastIntent = Intent(Constant.SRI_GEO_FENCE)
broadCastIntent.putExtra(Constant.KEY_GEOFENCE_STATE, isInside)
broadCastIntent.putExtra(Constant.KEY_GEOFENCE_LIST, mGeofencList)
LocalBroadcastManager.getInstance(this).sendBroadcast(broadCastIntent)
}
}
Then you just have to start the LocationService as follows:
val locationIntent = Intent(activity, LocationService::class.java)
activity.startService(locationIntent)
It has been tested and working perfectly. If there is any question, please approach me.
Thanks
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
Let me show you what i have done for a similar task. Below code has been used to achieve geofencing.
class LocationService : Service(), GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
var mLocationManager: LocationManager? = null
var googleApiClient: GoogleApiClient? = null
var pendingIntent: PendingIntent? = null
var geofencingRequest: GeofencingRequest? = null
var mGeofenceList: ArrayList<Geofence>? = null
private inner class LocationListener(provider: String) : android.location.LocationListener {
private var mLastLocation: Location = Location(provider)
override fun onLocationChanged(location: Location) {
mLastLocation.set(location)
}
override fun onProviderDisabled(provider: String) {}
override fun onProviderEnabled(provider: String) {}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
}
internal var mLocationListeners = arrayOf<android.location.LocationListener>(LocationListener(LocationManager.GPS_PROVIDER), LocationListener(LocationManager.NETWORK_PROVIDER))
override fun onBind(arg0: Intent): IBinder? {
return null
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
mGeofenceList = ArrayList()
populateGeofenceList()
super.onStartCommand(intent, flags, startId)
return Service.START_STICKY
}
override fun onCreate() {
initializeLocationManager()
try {
mLocationManager!!.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, Constant.LOCATION_INTERVAL.toLong(), Constant.LOCATION_DISTANCE, mLocationListeners[1])
} catch (ex: java.lang.SecurityException) {
ex.printStackTrace()
} catch (ex: IllegalArgumentException) {
ex.printStackTrace()
}
try {
mLocationManager!!.requestLocationUpdates(
LocationManager.GPS_PROVIDER, Constant.LOCATION_INTERVAL.toLong(), Constant.LOCATION_DISTANCE,
mLocationListeners[0])
} catch (ex: java.lang.SecurityException) {
ex.printStackTrace()
} catch (ex: IllegalArgumentException) {
ex.printStackTrace()
}
}
override fun onDestroy() {
super.onDestroy()
if (mLocationManager != null) {
for (i in mLocationListeners.indices) {
try {
mLocationManager!!.removeUpdates(mLocationListeners[i])
} catch (ex: Exception) {
ex.printStackTrace()
}
}
}
}
private fun initializeLocationManager() {
googleApiClient = GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build()
googleApiClient!!.connect()
if (mLocationManager == null) {
mLocationManager = applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
}
}
private fun startLocationMonitor() {
val locationRequest = LocationRequest.create()
.setInterval(Constant.LOCATION_INTERVAL.toLong())
.setFastestInterval(Constant.LOCATION_INTERVAL.toLong())
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
try {
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, object : com.google.android.gms.location.LocationListener {
override fun onLocationChanged(location: Location) {
DashBoardActivity.latitude = location.latitude
DashBoardActivity.longitude = location.longitude
if (BuildConfig.DEBUG) {
Log.e("LocationChanged:", location.latitude.toString() + " ," + location.longitude)
}
}
})
} catch (e: SecurityException) {
e.printStackTrace()
}
}
private fun startGeofencing() {
pendingIntent = getGeofencePendingIntent()
geofencingRequest = GeofencingRequest.Builder()
.setInitialTrigger(Geofence.GEOFENCE_TRANSITION_ENTER)
.addGeofences(mGeofenceList)
.build()
if (googleApiClient?.isConnected!!) {
try {
LocationServices.GeofencingApi.addGeofences(googleApiClient, geofencingRequest, pendingIntent).setResultCallback(object : ResultCallback<Status> {
override fun onResult(status: Status) {
}
})
} catch (e: SecurityException) {
e.printStackTrace()
}
}
}
private fun populateGeofenceList() {
for (entry in Constant.AREA_LANDMARKS.entries) { // Replace with your Location List
mGeofenceList?.add(Geofence.Builder()
.setRequestId(entry.key)
.setCircularRegion(entry.value.latitude, entry.value.longitude, Constant.GEOFENCE_RADIUS_IN_METERS)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setNotificationResponsiveness(1000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT)
.build())
}
}
private fun getGeofencePendingIntent(): PendingIntent? {
if (pendingIntent != null) {
return pendingIntent
}
val intent = Intent(this, GeofenceRegistrationService::class.java)
pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
return pendingIntent
}
override fun onConnected(bundle: Bundle?) {
startGeofencing()
startLocationMonitor()
}
override fun onConnectionSuspended(i: Int) {}
override fun onConnectionFailed(connectionResult: ConnectionResult) {}
}
For getting the geofence events, i have used below code:
class GeofenceRegistrationService : IntentService("GeoIntentService") {
val TAG = "GeoIntentService"
var mGeofencList: ArrayList<Geofence>? = null
override fun onHandleIntent(intent: Intent?) {
mGeofencList = ArrayList()
val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent.hasError()) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "Error" + geofencingEvent.errorCode)
}
} else {
try {
val transaction = geofencingEvent.geofenceTransition
val geofences = geofencingEvent.triggeringGeofences
for (i in 0 until geofences.size) {
mGeofencList?.add(geofences[i])
}
if (transaction == Geofence.GEOFENCE_TRANSITION_ENTER) {
sendBroadCast(true)
if (BuildConfig.DEBUG) {
Log.d(TAG, "You are inside Geofenced area")
}
}
if (transaction == Geofence.GEOFENCE_TRANSITION_EXIT) {
sendBroadCast(false)
if (BuildConfig.DEBUG) {
Log.d(TAG, "You are outside Geofenced area")
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
private fun sendBroadCast(isInside: Boolean) {
val broadCastIntent = Intent(Constant.SRI_GEO_FENCE)
broadCastIntent.putExtra(Constant.KEY_GEOFENCE_STATE, isInside)
broadCastIntent.putExtra(Constant.KEY_GEOFENCE_LIST, mGeofencList)
LocalBroadcastManager.getInstance(this).sendBroadcast(broadCastIntent)
}
}
Then you just have to start the LocationService as follows:
val locationIntent = Intent(activity, LocationService::class.java)
activity.startService(locationIntent)
It has been tested and working perfectly. If there is any question, please approach me.
Thanks
add a comment |
up vote
0
down vote
Let me show you what i have done for a similar task. Below code has been used to achieve geofencing.
class LocationService : Service(), GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
var mLocationManager: LocationManager? = null
var googleApiClient: GoogleApiClient? = null
var pendingIntent: PendingIntent? = null
var geofencingRequest: GeofencingRequest? = null
var mGeofenceList: ArrayList<Geofence>? = null
private inner class LocationListener(provider: String) : android.location.LocationListener {
private var mLastLocation: Location = Location(provider)
override fun onLocationChanged(location: Location) {
mLastLocation.set(location)
}
override fun onProviderDisabled(provider: String) {}
override fun onProviderEnabled(provider: String) {}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
}
internal var mLocationListeners = arrayOf<android.location.LocationListener>(LocationListener(LocationManager.GPS_PROVIDER), LocationListener(LocationManager.NETWORK_PROVIDER))
override fun onBind(arg0: Intent): IBinder? {
return null
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
mGeofenceList = ArrayList()
populateGeofenceList()
super.onStartCommand(intent, flags, startId)
return Service.START_STICKY
}
override fun onCreate() {
initializeLocationManager()
try {
mLocationManager!!.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, Constant.LOCATION_INTERVAL.toLong(), Constant.LOCATION_DISTANCE, mLocationListeners[1])
} catch (ex: java.lang.SecurityException) {
ex.printStackTrace()
} catch (ex: IllegalArgumentException) {
ex.printStackTrace()
}
try {
mLocationManager!!.requestLocationUpdates(
LocationManager.GPS_PROVIDER, Constant.LOCATION_INTERVAL.toLong(), Constant.LOCATION_DISTANCE,
mLocationListeners[0])
} catch (ex: java.lang.SecurityException) {
ex.printStackTrace()
} catch (ex: IllegalArgumentException) {
ex.printStackTrace()
}
}
override fun onDestroy() {
super.onDestroy()
if (mLocationManager != null) {
for (i in mLocationListeners.indices) {
try {
mLocationManager!!.removeUpdates(mLocationListeners[i])
} catch (ex: Exception) {
ex.printStackTrace()
}
}
}
}
private fun initializeLocationManager() {
googleApiClient = GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build()
googleApiClient!!.connect()
if (mLocationManager == null) {
mLocationManager = applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
}
}
private fun startLocationMonitor() {
val locationRequest = LocationRequest.create()
.setInterval(Constant.LOCATION_INTERVAL.toLong())
.setFastestInterval(Constant.LOCATION_INTERVAL.toLong())
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
try {
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, object : com.google.android.gms.location.LocationListener {
override fun onLocationChanged(location: Location) {
DashBoardActivity.latitude = location.latitude
DashBoardActivity.longitude = location.longitude
if (BuildConfig.DEBUG) {
Log.e("LocationChanged:", location.latitude.toString() + " ," + location.longitude)
}
}
})
} catch (e: SecurityException) {
e.printStackTrace()
}
}
private fun startGeofencing() {
pendingIntent = getGeofencePendingIntent()
geofencingRequest = GeofencingRequest.Builder()
.setInitialTrigger(Geofence.GEOFENCE_TRANSITION_ENTER)
.addGeofences(mGeofenceList)
.build()
if (googleApiClient?.isConnected!!) {
try {
LocationServices.GeofencingApi.addGeofences(googleApiClient, geofencingRequest, pendingIntent).setResultCallback(object : ResultCallback<Status> {
override fun onResult(status: Status) {
}
})
} catch (e: SecurityException) {
e.printStackTrace()
}
}
}
private fun populateGeofenceList() {
for (entry in Constant.AREA_LANDMARKS.entries) { // Replace with your Location List
mGeofenceList?.add(Geofence.Builder()
.setRequestId(entry.key)
.setCircularRegion(entry.value.latitude, entry.value.longitude, Constant.GEOFENCE_RADIUS_IN_METERS)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setNotificationResponsiveness(1000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT)
.build())
}
}
private fun getGeofencePendingIntent(): PendingIntent? {
if (pendingIntent != null) {
return pendingIntent
}
val intent = Intent(this, GeofenceRegistrationService::class.java)
pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
return pendingIntent
}
override fun onConnected(bundle: Bundle?) {
startGeofencing()
startLocationMonitor()
}
override fun onConnectionSuspended(i: Int) {}
override fun onConnectionFailed(connectionResult: ConnectionResult) {}
}
For getting the geofence events, i have used below code:
class GeofenceRegistrationService : IntentService("GeoIntentService") {
val TAG = "GeoIntentService"
var mGeofencList: ArrayList<Geofence>? = null
override fun onHandleIntent(intent: Intent?) {
mGeofencList = ArrayList()
val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent.hasError()) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "Error" + geofencingEvent.errorCode)
}
} else {
try {
val transaction = geofencingEvent.geofenceTransition
val geofences = geofencingEvent.triggeringGeofences
for (i in 0 until geofences.size) {
mGeofencList?.add(geofences[i])
}
if (transaction == Geofence.GEOFENCE_TRANSITION_ENTER) {
sendBroadCast(true)
if (BuildConfig.DEBUG) {
Log.d(TAG, "You are inside Geofenced area")
}
}
if (transaction == Geofence.GEOFENCE_TRANSITION_EXIT) {
sendBroadCast(false)
if (BuildConfig.DEBUG) {
Log.d(TAG, "You are outside Geofenced area")
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
private fun sendBroadCast(isInside: Boolean) {
val broadCastIntent = Intent(Constant.SRI_GEO_FENCE)
broadCastIntent.putExtra(Constant.KEY_GEOFENCE_STATE, isInside)
broadCastIntent.putExtra(Constant.KEY_GEOFENCE_LIST, mGeofencList)
LocalBroadcastManager.getInstance(this).sendBroadcast(broadCastIntent)
}
}
Then you just have to start the LocationService as follows:
val locationIntent = Intent(activity, LocationService::class.java)
activity.startService(locationIntent)
It has been tested and working perfectly. If there is any question, please approach me.
Thanks
add a comment |
up vote
0
down vote
up vote
0
down vote
Let me show you what i have done for a similar task. Below code has been used to achieve geofencing.
class LocationService : Service(), GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
var mLocationManager: LocationManager? = null
var googleApiClient: GoogleApiClient? = null
var pendingIntent: PendingIntent? = null
var geofencingRequest: GeofencingRequest? = null
var mGeofenceList: ArrayList<Geofence>? = null
private inner class LocationListener(provider: String) : android.location.LocationListener {
private var mLastLocation: Location = Location(provider)
override fun onLocationChanged(location: Location) {
mLastLocation.set(location)
}
override fun onProviderDisabled(provider: String) {}
override fun onProviderEnabled(provider: String) {}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
}
internal var mLocationListeners = arrayOf<android.location.LocationListener>(LocationListener(LocationManager.GPS_PROVIDER), LocationListener(LocationManager.NETWORK_PROVIDER))
override fun onBind(arg0: Intent): IBinder? {
return null
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
mGeofenceList = ArrayList()
populateGeofenceList()
super.onStartCommand(intent, flags, startId)
return Service.START_STICKY
}
override fun onCreate() {
initializeLocationManager()
try {
mLocationManager!!.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, Constant.LOCATION_INTERVAL.toLong(), Constant.LOCATION_DISTANCE, mLocationListeners[1])
} catch (ex: java.lang.SecurityException) {
ex.printStackTrace()
} catch (ex: IllegalArgumentException) {
ex.printStackTrace()
}
try {
mLocationManager!!.requestLocationUpdates(
LocationManager.GPS_PROVIDER, Constant.LOCATION_INTERVAL.toLong(), Constant.LOCATION_DISTANCE,
mLocationListeners[0])
} catch (ex: java.lang.SecurityException) {
ex.printStackTrace()
} catch (ex: IllegalArgumentException) {
ex.printStackTrace()
}
}
override fun onDestroy() {
super.onDestroy()
if (mLocationManager != null) {
for (i in mLocationListeners.indices) {
try {
mLocationManager!!.removeUpdates(mLocationListeners[i])
} catch (ex: Exception) {
ex.printStackTrace()
}
}
}
}
private fun initializeLocationManager() {
googleApiClient = GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build()
googleApiClient!!.connect()
if (mLocationManager == null) {
mLocationManager = applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
}
}
private fun startLocationMonitor() {
val locationRequest = LocationRequest.create()
.setInterval(Constant.LOCATION_INTERVAL.toLong())
.setFastestInterval(Constant.LOCATION_INTERVAL.toLong())
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
try {
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, object : com.google.android.gms.location.LocationListener {
override fun onLocationChanged(location: Location) {
DashBoardActivity.latitude = location.latitude
DashBoardActivity.longitude = location.longitude
if (BuildConfig.DEBUG) {
Log.e("LocationChanged:", location.latitude.toString() + " ," + location.longitude)
}
}
})
} catch (e: SecurityException) {
e.printStackTrace()
}
}
private fun startGeofencing() {
pendingIntent = getGeofencePendingIntent()
geofencingRequest = GeofencingRequest.Builder()
.setInitialTrigger(Geofence.GEOFENCE_TRANSITION_ENTER)
.addGeofences(mGeofenceList)
.build()
if (googleApiClient?.isConnected!!) {
try {
LocationServices.GeofencingApi.addGeofences(googleApiClient, geofencingRequest, pendingIntent).setResultCallback(object : ResultCallback<Status> {
override fun onResult(status: Status) {
}
})
} catch (e: SecurityException) {
e.printStackTrace()
}
}
}
private fun populateGeofenceList() {
for (entry in Constant.AREA_LANDMARKS.entries) { // Replace with your Location List
mGeofenceList?.add(Geofence.Builder()
.setRequestId(entry.key)
.setCircularRegion(entry.value.latitude, entry.value.longitude, Constant.GEOFENCE_RADIUS_IN_METERS)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setNotificationResponsiveness(1000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT)
.build())
}
}
private fun getGeofencePendingIntent(): PendingIntent? {
if (pendingIntent != null) {
return pendingIntent
}
val intent = Intent(this, GeofenceRegistrationService::class.java)
pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
return pendingIntent
}
override fun onConnected(bundle: Bundle?) {
startGeofencing()
startLocationMonitor()
}
override fun onConnectionSuspended(i: Int) {}
override fun onConnectionFailed(connectionResult: ConnectionResult) {}
}
For getting the geofence events, i have used below code:
class GeofenceRegistrationService : IntentService("GeoIntentService") {
val TAG = "GeoIntentService"
var mGeofencList: ArrayList<Geofence>? = null
override fun onHandleIntent(intent: Intent?) {
mGeofencList = ArrayList()
val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent.hasError()) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "Error" + geofencingEvent.errorCode)
}
} else {
try {
val transaction = geofencingEvent.geofenceTransition
val geofences = geofencingEvent.triggeringGeofences
for (i in 0 until geofences.size) {
mGeofencList?.add(geofences[i])
}
if (transaction == Geofence.GEOFENCE_TRANSITION_ENTER) {
sendBroadCast(true)
if (BuildConfig.DEBUG) {
Log.d(TAG, "You are inside Geofenced area")
}
}
if (transaction == Geofence.GEOFENCE_TRANSITION_EXIT) {
sendBroadCast(false)
if (BuildConfig.DEBUG) {
Log.d(TAG, "You are outside Geofenced area")
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
private fun sendBroadCast(isInside: Boolean) {
val broadCastIntent = Intent(Constant.SRI_GEO_FENCE)
broadCastIntent.putExtra(Constant.KEY_GEOFENCE_STATE, isInside)
broadCastIntent.putExtra(Constant.KEY_GEOFENCE_LIST, mGeofencList)
LocalBroadcastManager.getInstance(this).sendBroadcast(broadCastIntent)
}
}
Then you just have to start the LocationService as follows:
val locationIntent = Intent(activity, LocationService::class.java)
activity.startService(locationIntent)
It has been tested and working perfectly. If there is any question, please approach me.
Thanks
Let me show you what i have done for a similar task. Below code has been used to achieve geofencing.
class LocationService : Service(), GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
var mLocationManager: LocationManager? = null
var googleApiClient: GoogleApiClient? = null
var pendingIntent: PendingIntent? = null
var geofencingRequest: GeofencingRequest? = null
var mGeofenceList: ArrayList<Geofence>? = null
private inner class LocationListener(provider: String) : android.location.LocationListener {
private var mLastLocation: Location = Location(provider)
override fun onLocationChanged(location: Location) {
mLastLocation.set(location)
}
override fun onProviderDisabled(provider: String) {}
override fun onProviderEnabled(provider: String) {}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
}
internal var mLocationListeners = arrayOf<android.location.LocationListener>(LocationListener(LocationManager.GPS_PROVIDER), LocationListener(LocationManager.NETWORK_PROVIDER))
override fun onBind(arg0: Intent): IBinder? {
return null
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
mGeofenceList = ArrayList()
populateGeofenceList()
super.onStartCommand(intent, flags, startId)
return Service.START_STICKY
}
override fun onCreate() {
initializeLocationManager()
try {
mLocationManager!!.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, Constant.LOCATION_INTERVAL.toLong(), Constant.LOCATION_DISTANCE, mLocationListeners[1])
} catch (ex: java.lang.SecurityException) {
ex.printStackTrace()
} catch (ex: IllegalArgumentException) {
ex.printStackTrace()
}
try {
mLocationManager!!.requestLocationUpdates(
LocationManager.GPS_PROVIDER, Constant.LOCATION_INTERVAL.toLong(), Constant.LOCATION_DISTANCE,
mLocationListeners[0])
} catch (ex: java.lang.SecurityException) {
ex.printStackTrace()
} catch (ex: IllegalArgumentException) {
ex.printStackTrace()
}
}
override fun onDestroy() {
super.onDestroy()
if (mLocationManager != null) {
for (i in mLocationListeners.indices) {
try {
mLocationManager!!.removeUpdates(mLocationListeners[i])
} catch (ex: Exception) {
ex.printStackTrace()
}
}
}
}
private fun initializeLocationManager() {
googleApiClient = GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build()
googleApiClient!!.connect()
if (mLocationManager == null) {
mLocationManager = applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
}
}
private fun startLocationMonitor() {
val locationRequest = LocationRequest.create()
.setInterval(Constant.LOCATION_INTERVAL.toLong())
.setFastestInterval(Constant.LOCATION_INTERVAL.toLong())
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
try {
LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient, locationRequest, object : com.google.android.gms.location.LocationListener {
override fun onLocationChanged(location: Location) {
DashBoardActivity.latitude = location.latitude
DashBoardActivity.longitude = location.longitude
if (BuildConfig.DEBUG) {
Log.e("LocationChanged:", location.latitude.toString() + " ," + location.longitude)
}
}
})
} catch (e: SecurityException) {
e.printStackTrace()
}
}
private fun startGeofencing() {
pendingIntent = getGeofencePendingIntent()
geofencingRequest = GeofencingRequest.Builder()
.setInitialTrigger(Geofence.GEOFENCE_TRANSITION_ENTER)
.addGeofences(mGeofenceList)
.build()
if (googleApiClient?.isConnected!!) {
try {
LocationServices.GeofencingApi.addGeofences(googleApiClient, geofencingRequest, pendingIntent).setResultCallback(object : ResultCallback<Status> {
override fun onResult(status: Status) {
}
})
} catch (e: SecurityException) {
e.printStackTrace()
}
}
}
private fun populateGeofenceList() {
for (entry in Constant.AREA_LANDMARKS.entries) { // Replace with your Location List
mGeofenceList?.add(Geofence.Builder()
.setRequestId(entry.key)
.setCircularRegion(entry.value.latitude, entry.value.longitude, Constant.GEOFENCE_RADIUS_IN_METERS)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setNotificationResponsiveness(1000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT)
.build())
}
}
private fun getGeofencePendingIntent(): PendingIntent? {
if (pendingIntent != null) {
return pendingIntent
}
val intent = Intent(this, GeofenceRegistrationService::class.java)
pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
return pendingIntent
}
override fun onConnected(bundle: Bundle?) {
startGeofencing()
startLocationMonitor()
}
override fun onConnectionSuspended(i: Int) {}
override fun onConnectionFailed(connectionResult: ConnectionResult) {}
}
For getting the geofence events, i have used below code:
class GeofenceRegistrationService : IntentService("GeoIntentService") {
val TAG = "GeoIntentService"
var mGeofencList: ArrayList<Geofence>? = null
override fun onHandleIntent(intent: Intent?) {
mGeofencList = ArrayList()
val geofencingEvent = GeofencingEvent.fromIntent(intent)
if (geofencingEvent.hasError()) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "Error" + geofencingEvent.errorCode)
}
} else {
try {
val transaction = geofencingEvent.geofenceTransition
val geofences = geofencingEvent.triggeringGeofences
for (i in 0 until geofences.size) {
mGeofencList?.add(geofences[i])
}
if (transaction == Geofence.GEOFENCE_TRANSITION_ENTER) {
sendBroadCast(true)
if (BuildConfig.DEBUG) {
Log.d(TAG, "You are inside Geofenced area")
}
}
if (transaction == Geofence.GEOFENCE_TRANSITION_EXIT) {
sendBroadCast(false)
if (BuildConfig.DEBUG) {
Log.d(TAG, "You are outside Geofenced area")
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
private fun sendBroadCast(isInside: Boolean) {
val broadCastIntent = Intent(Constant.SRI_GEO_FENCE)
broadCastIntent.putExtra(Constant.KEY_GEOFENCE_STATE, isInside)
broadCastIntent.putExtra(Constant.KEY_GEOFENCE_LIST, mGeofencList)
LocalBroadcastManager.getInstance(this).sendBroadcast(broadCastIntent)
}
}
Then you just have to start the LocationService as follows:
val locationIntent = Intent(activity, LocationService::class.java)
activity.startService(locationIntent)
It has been tested and working perfectly. If there is any question, please approach me.
Thanks
answered Nov 21 at 11:48
Vikash Bijarniya
606
606
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53405841%2fgeofence-triggering-issues-in-android%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
please post the code
– Vikash Bijarniya
Nov 21 at 5:47
@VikashBijarniya Added source code.
– Rahul Rastogi
Nov 21 at 6:00