Skip to content

Instantly share code, notes, and snippets.

@LuchoD03
Created October 11, 2022 01:29
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Embed
What would you like to do?
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.Build
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 = 200
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
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
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("Ubicación Actual"))?.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 = getBroadcast(
applicationContext, 0, intent, FLAG_UPDATE_CURRENT
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
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)
}
} 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 para funcionar en Android 10 y mayores",
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 (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (grantResults.isNotEmpty() && grantResults[2] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(
this,
"Esta aplicación necesita acceso a la ubicación en segundo plano para funcionar en Android 10 y mayores",
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
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
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())
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment