mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-19 03:29:28 +01:00
596 lines
22 KiB
Kotlin
596 lines
22 KiB
Kotlin
/*
|
|
* Nextcloud Talk - Android Client
|
|
*
|
|
* SPDX-FileCopyrightText: 2023 Ezhil Shanmugham <ezhil56x.contact@gmail.com>
|
|
* SPDX-FileCopyrightText: 2021 Marcel Hibbe <dev@mhibbe.de>
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
package com.nextcloud.talk.location
|
|
|
|
import android.Manifest
|
|
import android.app.Activity
|
|
import android.app.SearchManager
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.content.pm.PackageManager
|
|
import android.location.Location
|
|
import android.location.LocationListener
|
|
import android.location.LocationManager
|
|
import android.os.Bundle
|
|
import android.text.InputType
|
|
import android.util.Log
|
|
import android.view.Menu
|
|
import android.view.MenuItem
|
|
import android.view.View
|
|
import android.view.inputmethod.EditorInfo
|
|
import androidx.activity.OnBackPressedCallback
|
|
import androidx.appcompat.widget.SearchView
|
|
import androidx.core.content.PermissionChecker
|
|
import androidx.core.content.res.ResourcesCompat
|
|
import androidx.core.graphics.drawable.toDrawable
|
|
import androidx.core.view.MenuItemCompat
|
|
import androidx.preference.PreferenceManager
|
|
import autodagger.AutoInjector
|
|
import com.google.android.material.snackbar.Snackbar
|
|
import com.nextcloud.talk.R
|
|
import com.nextcloud.talk.activities.BaseActivity
|
|
import com.nextcloud.talk.api.NcApi
|
|
import com.nextcloud.talk.application.NextcloudTalkApplication
|
|
import com.nextcloud.talk.databinding.ActivityLocationBinding
|
|
import com.nextcloud.talk.models.json.generic.GenericOverall
|
|
import com.nextcloud.talk.users.UserManager
|
|
import com.nextcloud.talk.utils.ApiUtils
|
|
import com.nextcloud.talk.utils.DisplayUtils
|
|
import com.nextcloud.talk.utils.bundle.BundleKeys
|
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CHAT_API_VERSION
|
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_GEOCODING_RESULT
|
|
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
|
|
import fr.dudie.nominatim.client.TalkJsonNominatimClient
|
|
import fr.dudie.nominatim.model.Address
|
|
import io.reactivex.Observer
|
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
|
import io.reactivex.disposables.Disposable
|
|
import io.reactivex.schedulers.Schedulers
|
|
import kotlinx.coroutines.CoroutineScope
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.launch
|
|
import kotlinx.coroutines.withContext
|
|
import okhttp3.OkHttpClient
|
|
import org.osmdroid.config.Configuration.getInstance
|
|
import org.osmdroid.events.DelayedMapListener
|
|
import org.osmdroid.events.MapListener
|
|
import org.osmdroid.events.ScrollEvent
|
|
import org.osmdroid.events.ZoomEvent
|
|
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
|
|
import org.osmdroid.util.GeoPoint
|
|
import org.osmdroid.views.overlay.CopyrightOverlay
|
|
import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider
|
|
import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay
|
|
import javax.inject.Inject
|
|
|
|
@AutoInjector(NextcloudTalkApplication::class)
|
|
class LocationPickerActivity :
|
|
BaseActivity(),
|
|
SearchView.OnQueryTextListener,
|
|
LocationListener {
|
|
|
|
private lateinit var binding: ActivityLocationBinding
|
|
|
|
@Inject
|
|
lateinit var ncApi: NcApi
|
|
|
|
@Inject
|
|
lateinit var userManager: UserManager
|
|
|
|
@Inject
|
|
lateinit var okHttpClient: OkHttpClient
|
|
|
|
var nominatimClient: TalkJsonNominatimClient? = null
|
|
|
|
lateinit var roomToken: String
|
|
private var chatApiVersion: Int = 1
|
|
var geocodingResult: GeocodingResult? = null
|
|
|
|
var myLocation: GeoPoint = GeoPoint(COORDINATE_ZERO, COORDINATE_ZERO)
|
|
private var locationManager: LocationManager? = null
|
|
private lateinit var locationOverlay: MyLocationNewOverlay
|
|
|
|
var moveToCurrentLocation: Boolean = true
|
|
var readyToShareLocation: Boolean = false
|
|
|
|
private var mapCenterLat: Double = 0.0
|
|
private var mapCenterLon: Double = 0.0
|
|
|
|
var searchItem: MenuItem? = null
|
|
var searchView: SearchView? = null
|
|
|
|
private val onBackPressedCallback = object : OnBackPressedCallback(true) {
|
|
override fun handleOnBackPressed() {
|
|
setResult(Activity.RESULT_CANCELED)
|
|
finish()
|
|
}
|
|
}
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
|
|
|
|
roomToken = intent.getStringExtra(KEY_ROOM_TOKEN)!!
|
|
chatApiVersion = intent.getIntExtra(KEY_CHAT_API_VERSION, 1)
|
|
geocodingResult = intent.getParcelableExtra(KEY_GEOCODING_RESULT)
|
|
|
|
if (savedInstanceState != null) {
|
|
moveToCurrentLocation = savedInstanceState.getBoolean("moveToCurrentLocation") == true
|
|
mapCenterLat = savedInstanceState.getDouble("mapCenterLat")
|
|
mapCenterLon = savedInstanceState.getDouble("mapCenterLon")
|
|
geocodingResult = savedInstanceState.getParcelable("geocodingResult")
|
|
}
|
|
|
|
binding = ActivityLocationBinding.inflate(layoutInflater)
|
|
setupActionBar()
|
|
setContentView(binding.root)
|
|
initSystemBars()
|
|
|
|
getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context))
|
|
|
|
onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
|
|
}
|
|
|
|
override fun onStart() {
|
|
super.onStart()
|
|
initMap()
|
|
}
|
|
|
|
override fun onResume() {
|
|
super.onResume()
|
|
|
|
if (geocodingResult != null) {
|
|
moveToCurrentLocation = false
|
|
}
|
|
|
|
setLocationDescription(false, geocodingResult != null)
|
|
binding.shareLocation.isClickable = false
|
|
binding.shareLocation.setOnClickListener {
|
|
if (readyToShareLocation) {
|
|
shareLocation(
|
|
binding.map.mapCenter?.latitude,
|
|
binding.map.mapCenter?.longitude,
|
|
binding.placeName.text.toString()
|
|
)
|
|
} else {
|
|
Log.w(TAG, "readyToShareLocation was false while user tried to share location.")
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onSaveInstanceState(bundle: Bundle) {
|
|
super.onSaveInstanceState(bundle)
|
|
bundle.putBoolean("moveToCurrentLocation", moveToCurrentLocation)
|
|
bundle.putDouble("mapCenterLat", binding.map.mapCenter.latitude)
|
|
bundle.putDouble("mapCenterLon", binding.map.mapCenter.longitude)
|
|
bundle.putParcelable("geocodingResult", geocodingResult)
|
|
}
|
|
|
|
private fun setupActionBar() {
|
|
setSupportActionBar(binding.locationPickerToolbar)
|
|
binding.locationPickerToolbar.setNavigationOnClickListener {
|
|
onBackPressedDispatcher.onBackPressed()
|
|
}
|
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
|
supportActionBar?.setDisplayShowHomeEnabled(true)
|
|
supportActionBar?.setIcon(resources!!.getColor(android.R.color.transparent, null).toDrawable())
|
|
supportActionBar?.title = context.getString(R.string.nc_share_location)
|
|
viewThemeUtils.material.themeToolbar(binding.locationPickerToolbar)
|
|
}
|
|
|
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
|
super.onCreateOptionsMenu(menu)
|
|
menuInflater.inflate(R.menu.menu_locationpicker, menu)
|
|
return true
|
|
}
|
|
|
|
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
|
super.onPrepareOptionsMenu(menu)
|
|
searchItem = menu.findItem(R.id.location_action_search)
|
|
initSearchView()
|
|
return true
|
|
}
|
|
|
|
@Suppress("Detekt.TooGenericExceptionCaught")
|
|
override fun onStop() {
|
|
super.onStop()
|
|
|
|
try {
|
|
locationManager!!.removeUpdates(this)
|
|
} catch (e: Exception) {
|
|
Log.e(TAG, "error when trying to remove updates for location Manager", e)
|
|
}
|
|
|
|
locationOverlay.disableMyLocation()
|
|
}
|
|
|
|
private fun initSearchView() {
|
|
val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
|
|
if (searchItem != null) {
|
|
searchView = MenuItemCompat.getActionView(searchItem) as SearchView
|
|
searchView?.maxWidth = Int.MAX_VALUE
|
|
searchView?.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
|
|
var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
|
|
if (appPreferences!!.isKeyboardIncognito) {
|
|
imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
|
|
}
|
|
searchView?.imeOptions = imeOptions
|
|
searchView?.queryHint = resources!!.getString(R.string.nc_search)
|
|
searchView?.setSearchableInfo(searchManager.getSearchableInfo(componentName))
|
|
searchView?.setOnQueryTextListener(this)
|
|
}
|
|
}
|
|
|
|
override fun onQueryTextSubmit(query: String?): Boolean {
|
|
if (!query.isNullOrEmpty()) {
|
|
val intent = Intent(this, GeocodingActivity::class.java)
|
|
intent.putExtra(BundleKeys.KEY_GEOCODING_QUERY, query)
|
|
intent.putExtra(KEY_ROOM_TOKEN, roomToken)
|
|
intent.putExtra(KEY_CHAT_API_VERSION, chatApiVersion)
|
|
startActivity(intent)
|
|
}
|
|
return true
|
|
}
|
|
|
|
override fun onQueryTextChange(newText: String?): Boolean {
|
|
return true
|
|
}
|
|
|
|
@Suppress("Detekt.TooGenericExceptionCaught", "Detekt.ComplexMethod", "Detekt.LongMethod")
|
|
private fun initMap() {
|
|
binding.map.setTileSource(TileSourceFactory.MAPNIK)
|
|
binding.map.onResume()
|
|
|
|
locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
|
|
|
|
if (!isLocationPermissionsGranted()) {
|
|
requestLocationPermissions()
|
|
} else {
|
|
requestLocationUpdates()
|
|
}
|
|
|
|
val copyrightOverlay = CopyrightOverlay(context)
|
|
binding.map.overlays.add(copyrightOverlay)
|
|
|
|
binding.map.setMultiTouchControls(true)
|
|
binding.map.isTilesScaledToDpi = true
|
|
|
|
locationOverlay = MyLocationNewOverlay(GpsMyLocationProvider(context), binding.map)
|
|
locationOverlay.enableMyLocation()
|
|
locationOverlay.setPersonHotspot(PERSON_HOT_SPOT_X, PERSON_HOT_SPOT_Y)
|
|
locationOverlay.setPersonIcon(
|
|
DisplayUtils.getBitmap(
|
|
ResourcesCompat.getDrawable(resources!!, R.drawable.current_location_circle, null)!!
|
|
)
|
|
)
|
|
binding.map.overlays.add(locationOverlay)
|
|
|
|
val mapController = binding.map.controller
|
|
|
|
if (geocodingResult != null) {
|
|
mapController.setZoom(ZOOM_LEVEL_RECEIVED_RESULT)
|
|
} else {
|
|
mapController.setZoom(ZOOM_LEVEL_DEFAULT)
|
|
}
|
|
|
|
if (mapCenterLat != 0.0 && mapCenterLon != 0.0) {
|
|
mapController.setCenter(GeoPoint(mapCenterLat, mapCenterLon))
|
|
}
|
|
|
|
val zoomToCurrentPositionOnFirstFix = geocodingResult == null && moveToCurrentLocation
|
|
locationOverlay.runOnFirstFix {
|
|
if (locationOverlay.myLocation != null) {
|
|
myLocation = locationOverlay.myLocation
|
|
if (zoomToCurrentPositionOnFirstFix) {
|
|
runOnUiThread {
|
|
mapController.setZoom(ZOOM_LEVEL_DEFAULT)
|
|
mapController.setCenter(myLocation)
|
|
}
|
|
}
|
|
} else {
|
|
// locationOverlay.myLocation was null. might be an osmdroid bug?
|
|
// However that seems to be okay because runOnFirstFix is called twice somehow and the second time
|
|
// locationOverlay.myLocation is not null.
|
|
}
|
|
}
|
|
|
|
geocodingResult?.let {
|
|
if (it.lat != COORDINATE_ZERO && it.lon != COORDINATE_ZERO) {
|
|
mapController.setCenter(GeoPoint(it.lat, it.lon))
|
|
}
|
|
}
|
|
|
|
binding.centerMapButton.setOnClickListener {
|
|
if (myLocation.latitude == COORDINATE_ZERO && myLocation.longitude == COORDINATE_ZERO) {
|
|
Snackbar.make(
|
|
binding.root,
|
|
context.getString(R.string.nc_location_unknown),
|
|
Snackbar.LENGTH_LONG
|
|
).show()
|
|
} else {
|
|
mapController.animateTo(myLocation)
|
|
moveToCurrentLocation = true
|
|
}
|
|
}
|
|
|
|
binding.map.addMapListener(
|
|
delayedMapListener()
|
|
)
|
|
}
|
|
|
|
private fun delayedMapListener() =
|
|
DelayedMapListener(
|
|
object : MapListener {
|
|
@Suppress("Detekt.TooGenericExceptionCaught")
|
|
override fun onScroll(paramScrollEvent: ScrollEvent): Boolean {
|
|
try {
|
|
when {
|
|
moveToCurrentLocation -> {
|
|
setLocationDescription(isGpsLocation = true, isGeocodedResult = false)
|
|
moveToCurrentLocation = false
|
|
}
|
|
|
|
geocodingResult != null -> {
|
|
binding.shareLocation.isClickable = true
|
|
setLocationDescription(isGpsLocation = false, isGeocodedResult = true)
|
|
geocodingResult = null
|
|
}
|
|
|
|
else -> {
|
|
binding.shareLocation.isClickable = true
|
|
setLocationDescription(isGpsLocation = false, isGeocodedResult = false)
|
|
}
|
|
}
|
|
} catch (e: NullPointerException) {
|
|
Log.d(TAG, "UI already closed")
|
|
}
|
|
|
|
readyToShareLocation = true
|
|
return true
|
|
}
|
|
|
|
override fun onZoom(event: ZoomEvent): Boolean {
|
|
return false
|
|
}
|
|
}
|
|
)
|
|
|
|
@Suppress("Detekt.TooGenericExceptionCaught")
|
|
private fun requestLocationUpdates() {
|
|
try {
|
|
when {
|
|
locationManager!!.isProviderEnabled(LocationManager.NETWORK_PROVIDER) -> {
|
|
locationManager!!.requestLocationUpdates(
|
|
LocationManager.NETWORK_PROVIDER,
|
|
MIN_LOCATION_UPDATE_TIME,
|
|
MIN_LOCATION_UPDATE_DISTANCE,
|
|
this
|
|
)
|
|
}
|
|
|
|
locationManager!!.isProviderEnabled(LocationManager.GPS_PROVIDER) -> {
|
|
locationManager!!.requestLocationUpdates(
|
|
LocationManager.GPS_PROVIDER,
|
|
MIN_LOCATION_UPDATE_TIME,
|
|
MIN_LOCATION_UPDATE_DISTANCE,
|
|
this
|
|
)
|
|
Log.d(TAG, "LocationManager.NETWORK_PROVIDER falling back to LocationManager.GPS_PROVIDER")
|
|
}
|
|
|
|
else -> {
|
|
Log.e(
|
|
TAG,
|
|
"Error requesting location updates. Probably this is a phone without google services" +
|
|
" and there is no alternative like UnifiedNlp installed. Furthermore no GPS is " +
|
|
"supported."
|
|
)
|
|
Snackbar.make(binding.root, context.getString(R.string.nc_location_unknown), Snackbar.LENGTH_LONG)
|
|
.show()
|
|
}
|
|
}
|
|
} catch (e: SecurityException) {
|
|
Log.e(TAG, "Error when requesting location updates. Permissions may be missing.", e)
|
|
Snackbar.make(binding.root, context.getString(R.string.nc_location_unknown), Snackbar.LENGTH_LONG).show()
|
|
} catch (e: Exception) {
|
|
Log.e(TAG, "Error when requesting location updates.", e)
|
|
Snackbar.make(binding.root, context.getString(R.string.nc_common_error_sorry), Snackbar.LENGTH_LONG).show()
|
|
}
|
|
}
|
|
|
|
private fun setLocationDescription(isGpsLocation: Boolean, isGeocodedResult: Boolean) {
|
|
when {
|
|
isGpsLocation -> {
|
|
binding.shareLocationDescription.text = context!!.getText(R.string.nc_share_current_location)
|
|
binding.placeName.visibility = View.GONE
|
|
binding.placeName.text = ""
|
|
}
|
|
|
|
isGeocodedResult -> {
|
|
binding.shareLocationDescription.text = context!!.getText(R.string.nc_share_this_location)
|
|
binding.placeName.visibility = View.VISIBLE
|
|
binding.placeName.text = geocodingResult?.displayName
|
|
}
|
|
|
|
else -> {
|
|
binding.shareLocationDescription.text = context!!.getText(R.string.nc_share_this_location)
|
|
binding.placeName.visibility = View.GONE
|
|
binding.placeName.text = ""
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun shareLocation(selectedLat: Double?, selectedLon: Double?, locationName: String?) {
|
|
if (selectedLat != null || selectedLon != null) {
|
|
val name = locationName
|
|
if (name.isNullOrEmpty()) {
|
|
initGeocoder()
|
|
searchPlaceNameForCoordinates(selectedLat!!, selectedLon!!)
|
|
} else {
|
|
executeShareLocation(selectedLat, selectedLon, locationName)
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun executeShareLocation(selectedLat: Double?, selectedLon: Double?, locationName: String?) {
|
|
binding.roundedImageView.visibility = View.GONE
|
|
binding.sendingLocationProgressbar.visibility = View.VISIBLE
|
|
|
|
val objectId = "geo:$selectedLat,$selectedLon"
|
|
|
|
var locationNameToShare = locationName
|
|
if (locationNameToShare.isNullOrBlank()) {
|
|
locationNameToShare = resources.getString(R.string.nc_shared_location)
|
|
}
|
|
|
|
val metaData: String =
|
|
"{\"type\":\"geo-location\",\"id\":\"geo:$selectedLat,$selectedLon\",\"latitude\":\"$selectedLat\"," +
|
|
"\"longitude\":\"$selectedLon\",\"name\":\"$locationNameToShare\"}"
|
|
|
|
val currentUser = currentUserProvider.currentUser.blockingGet()
|
|
|
|
ncApi.sendLocation(
|
|
ApiUtils.getCredentials(currentUser.username, currentUser.token),
|
|
ApiUtils.getUrlToSendLocation(chatApiVersion, currentUser.baseUrl!!, roomToken),
|
|
"geo-location",
|
|
objectId,
|
|
metaData
|
|
)
|
|
.subscribeOn(Schedulers.io())
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
.subscribe(object : Observer<GenericOverall> {
|
|
override fun onSubscribe(d: Disposable) {
|
|
// unused atm
|
|
}
|
|
|
|
override fun onNext(t: GenericOverall) {
|
|
finish()
|
|
}
|
|
|
|
override fun onError(e: Throwable) {
|
|
Log.e(TAG, "error when trying to share location", e)
|
|
Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
|
|
finish()
|
|
}
|
|
|
|
override fun onComplete() {
|
|
// unused atm
|
|
}
|
|
})
|
|
}
|
|
|
|
private fun isLocationPermissionsGranted(): Boolean {
|
|
fun isCoarseLocationGranted(): Boolean {
|
|
return PermissionChecker.checkSelfPermission(
|
|
context,
|
|
Manifest.permission.ACCESS_COARSE_LOCATION
|
|
) == PermissionChecker.PERMISSION_GRANTED
|
|
}
|
|
|
|
fun isFineLocationGranted(): Boolean {
|
|
return PermissionChecker.checkSelfPermission(
|
|
context,
|
|
Manifest.permission.ACCESS_FINE_LOCATION
|
|
) == PermissionChecker.PERMISSION_GRANTED
|
|
}
|
|
|
|
return isCoarseLocationGranted() && isFineLocationGranted()
|
|
}
|
|
|
|
private fun requestLocationPermissions() {
|
|
requestPermissions(
|
|
arrayOf(
|
|
Manifest.permission.ACCESS_FINE_LOCATION,
|
|
Manifest.permission.ACCESS_COARSE_LOCATION
|
|
),
|
|
REQUEST_PERMISSIONS_REQUEST_CODE
|
|
)
|
|
}
|
|
|
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
|
|
|
fun areAllGranted(grantResults: IntArray): Boolean {
|
|
grantResults.forEach {
|
|
if (it == PackageManager.PERMISSION_DENIED) return false
|
|
}
|
|
return grantResults.isNotEmpty()
|
|
}
|
|
|
|
if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE && areAllGranted(grantResults)) {
|
|
initMap()
|
|
} else {
|
|
Snackbar.make(
|
|
binding.root,
|
|
context!!.getString(R.string.nc_location_permission_required),
|
|
Snackbar.LENGTH_LONG
|
|
).show()
|
|
}
|
|
}
|
|
|
|
private fun initGeocoder() {
|
|
val baseUrl = context!!.getString(R.string.osm_geocoder_url)
|
|
val email = context!!.getString(R.string.osm_geocoder_contact)
|
|
nominatimClient = TalkJsonNominatimClient(baseUrl, okHttpClient, email)
|
|
}
|
|
|
|
private fun searchPlaceNameForCoordinates(lat: Double, lon: Double): Boolean {
|
|
CoroutineScope(Dispatchers.IO).launch {
|
|
executeGeocodingRequest(lat, lon)
|
|
}
|
|
return true
|
|
}
|
|
|
|
@Suppress("Detekt.TooGenericExceptionCaught")
|
|
private suspend fun executeGeocodingRequest(lat: Double, lon: Double) {
|
|
var address: Address? = null
|
|
try {
|
|
address = nominatimClient!!.getAddress(lon, lat)
|
|
} catch (e: Exception) {
|
|
Log.e(TAG, "Failed to get geocoded addresses", e)
|
|
Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
|
|
}
|
|
updateResultOnMainThread(lat, lon, address?.displayName)
|
|
}
|
|
|
|
private suspend fun updateResultOnMainThread(lat: Double, lon: Double, addressName: String?) {
|
|
withContext(Dispatchers.Main) {
|
|
executeShareLocation(lat, lon, addressName)
|
|
}
|
|
}
|
|
|
|
override fun onLocationChanged(location: Location) {
|
|
myLocation = GeoPoint(location)
|
|
}
|
|
|
|
@Deprecated("Deprecated. This callback will never be invoked on Android Q and above.")
|
|
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
|
|
// empty
|
|
}
|
|
|
|
override fun onProviderEnabled(provider: String) {
|
|
// empty
|
|
}
|
|
|
|
override fun onProviderDisabled(provider: String) {
|
|
// empty
|
|
}
|
|
|
|
companion object {
|
|
private val TAG = LocationPickerActivity::class.java.simpleName
|
|
private const val REQUEST_PERMISSIONS_REQUEST_CODE = 1
|
|
private const val PERSON_HOT_SPOT_X: Float = 20.0F
|
|
private const val PERSON_HOT_SPOT_Y: Float = 20.0F
|
|
private const val ZOOM_LEVEL_RECEIVED_RESULT: Double = 14.0
|
|
private const val ZOOM_LEVEL_DEFAULT: Double = 14.0
|
|
private const val COORDINATE_ZERO: Double = 0.0
|
|
private const val MIN_LOCATION_UPDATE_TIME: Long = 30 * 1000L
|
|
private const val MIN_LOCATION_UPDATE_DISTANCE: Float = 0f
|
|
}
|
|
}
|