I'm having this problem where the only time the geofence triggers is only when I create a radius right where I'm standing at the time and when I start moving and entering other radios it won't trigger.
I'm pretty sure the problem is the pendingIntent FLAG, but I don't know how to solve it.
I have tried all the FLAGS, but some of them don't even work. This same code worked on API 29, but I can't get it to work on API 31. Any help is appreciated.
MAIN CODE
package com.geofenceApp.geofencing
import android.Manifest
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import com.google.android.gms.location.*
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.CircleOptions
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
import com.google.firebase.database.ktx.database
import com.google.firebase.ktx.Firebase
import kotlin.random.Random
const val GEOFENCE_RADIUS = 70
const val GEOFENCE_ID = "REMINDER_GEOFENCE_ID"
const val GEOFENCE_EXPIRATION = 10 * 24 * 60 * 60 * 1000 // 10 dias
const val GEOFENCE_DWELL_DELAY = 10 * 1000 // 10 segundos // 2 minutos
const val GEOFENCE_LOCATION_REQUEST_CODE = 12345
const val CAMERA_ZOOM_LEVEL = 13f
const val LOCATION_REQUEST_CODE = 123
class MapsActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var map: GoogleMap
private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var geofencingClient: GeofencingClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_maps)
val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
geofencingClient = LocationServices.getGeofencingClient(this)
}
override fun onMapReady(googleMap: GoogleMap) {
map = googleMap
map.uiSettings.isZoomControlsEnabled = true
if (!isLocationPermissionGranted()) {
val permissions = mutableListOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
permissions.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
ActivityCompat.requestPermissions(
this,
permissions.toTypedArray(),
LOCATION_REQUEST_CODE
)
} else {
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
}
this.map.isMyLocationEnabled = true
// Hace zoom a la ultima ubicacion conocida
fusedLocationClient.lastLocation.addOnSuccessListener {
if (it != null) {
with(map) {
val latLng = LatLng(it.latitude, it.longitude)
moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, CAMERA_ZOOM_LEVEL))
}
} else {
with(map) { //Hace zoom a la ubicacion actual
moveCamera(
CameraUpdateFactory.newLatLngZoom(
LatLng(-34.69787, -58.50459),
CAMERA_ZOOM_LEVEL
)
)
}
}
}
}
setLongClick(map)
setPoiClick(map)
}
private fun setPoiClick(map: GoogleMap) {
map.setOnPoiClickListener { poi ->
map.addMarker(
MarkerOptions()
.position(poi.latLng)
.title(poi.name)
)?.showInfoWindow()
}
}
private fun setLongClick(map: GoogleMap) {
map.setOnMapLongClickListener { latlng ->
map.addMarker(
MarkerOptions().position(latlng)
.title("Radio")
)?.showInfoWindow()
map.addCircle(
CircleOptions()
.center(latlng)
.strokeColor(Color.argb(50, 70, 70, 70))
.fillColor(Color.argb(70, 150, 150, 150))
.radius(GEOFENCE_RADIUS.toDouble())
)
map.moveCamera(CameraUpdateFactory.newLatLngZoom(latlng, CAMERA_ZOOM_LEVEL))
val database = Firebase.database
val reference = database.getReference("reminders")
val key = reference.push().key
if (key != null) {
val reminder = Reminder(key, latlng.latitude, latlng.longitude,"Entrando al radio en ${latlng.latitude} - ${latlng.longitude}")
reference.child(key).setValue(reminder)
}
createGeoFence(latlng, key!!, geofencingClient)
}
}
private fun createGeoFence(location: LatLng, key: String, geofencingClient: GeofencingClient) {
val geofence = Geofence.Builder()
.setRequestId(GEOFENCE_ID)
.setCircularRegion(location.latitude, location.longitude, GEOFENCE_RADIUS.toFloat())
.setExpirationDuration(GEOFENCE_EXPIRATION.toLong())
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_DWELL)
.setLoiteringDelay(GEOFENCE_DWELL_DELAY)
.build()
val geofenceRequest = GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.addGeofence(geofence)
.build()
val intent = Intent(this, GeofenceReceiver::class.java)
.putExtra("key", key)
.putExtra("message", "Entrada detectada al radio - ${location.latitude}, ${location.longitude}")
val pendingIntent = PendingIntent.getBroadcast(applicationContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE)
if (ContextCompat.checkSelfPermission(
applicationContext, Manifest.permission.ACCESS_BACKGROUND_LOCATION
) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
GEOFENCE_LOCATION_REQUEST_CODE
)
} else {
geofencingClient.addGeofences(geofenceRequest, pendingIntent)
}
}
private fun isLocationPermissionGranted() : Boolean {
return ContextCompat.checkSelfPermission(
this, Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(
applicationContext, Manifest.permission.ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == GEOFENCE_LOCATION_REQUEST_CODE) {
if (permissions.isNotEmpty() && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(
this,
"Esta aplicación necesita acceso a la ubicación en segundo plano",
Toast.LENGTH_SHORT
).show()
}
}
if (requestCode == LOCATION_REQUEST_CODE) {
if (
grantResults.isNotEmpty() && (
grantResults[0] == PackageManager.PERMISSION_GRANTED ||
grantResults[1] == PackageManager.PERMISSION_GRANTED)
) {
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
return
}
map.isMyLocationEnabled = true
onMapReady(map)
} else {
Toast.makeText(
this,
"La aplicación necesita permiso para funcionar",
Toast.LENGTH_LONG
).show()
}
if (grantResults.isNotEmpty() && grantResults[2] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(
this,
"Esta aplicación necesita acceso a la ubicación en segundo plano",
Toast.LENGTH_LONG
).show()
}
}
}
companion object {
fun removeGeofence(context: Context, triggeringGeofenceList: MutableList<Geofence>) {
val geofenceIdList = mutableListOf<String>()
for (entry in triggeringGeofenceList) {
geofenceIdList.add(entry.requestId)
}
LocationServices.getGeofencingClient(context).removeGeofences(geofenceIdList)
}
fun showNotification(context: Context?, message: String) {
val CHANNEL_ID = "REMINDER_NOTIFICATION_CHANNEL"
var notificationId = 1589
notificationId += Random(notificationId).nextInt(1, 30)
val notificationBuilder = NotificationCompat.Builder(context!!.applicationContext, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_alarm)
.setContentTitle(context.getString(R.string.app_name))
.setContentText(message)
.setStyle(
NotificationCompat.BigTextStyle().bigText(message)
)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channel = NotificationChannel(
CHANNEL_ID,
context.getString(R.string.app_name),
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = context.getString(R.string.app_name)
}
notificationManager.createNotificationChannel(channel)
notificationManager.notify(notificationId, notificationBuilder.build())
}
}
}
As I mentioned above this same code worked on API 29 but I need it to work on API 31 and is not working, I've been trying to solve this problem for the last 2 weeks.