Move tracker to gms location

This commit is contained in:
max-klaus 2021-01-16 22:02:46 +03:00
parent 57c27167ef
commit ade94c9932
6 changed files with 121 additions and 239 deletions

View file

@ -8,6 +8,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:name="net.osmand.telegram.TelegramApplication"
@ -46,6 +47,16 @@
</activity>
<service
android:name=".TelegramService"
android:label="@string/process_service"
android:exported="false"
android:foregroundServiceType="location">
<intent-filter>
<action android:name="net.osmand.telegram.TelegramService" />
</intent-filter>
</service>
<receiver
android:name=".InitAppBroadcastReceiver"
android:enabled="true"

View file

@ -152,4 +152,6 @@ dependencies {
implementation("com.github.HITGIF:TextFieldBoxes:1.4.5") {
exclude group: 'com.android.support'
}
implementation 'com.google.android.gms:play-services-location:17.1.0'
}

View file

@ -148,7 +148,6 @@ class TelegramApplication : Application() {
}
private fun startTelegramService(intent: Int) {
/*
var i = intent
val serviceIntent = Intent(this, TelegramService::class.java)
val telegramService = telegramService
@ -159,7 +158,6 @@ class TelegramApplication : Application() {
serviceIntent.putExtra(TelegramService.USAGE_INTENT, i)
serviceIntent.putExtra(TelegramService.SEND_LOCATION_INTERVAL, settings.sendMyLocInterval)
ContextCompat.startForegroundService(this, serviceIntent)
*/
}
fun startMyLocationService() {

View file

@ -3,22 +3,20 @@ package net.osmand.telegram
import android.annotation.SuppressLint
import android.content.Context
import android.hardware.*
import android.location.GpsStatus
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
import android.os.Looper
import android.util.Log
import com.google.android.gms.location.*
import net.osmand.PlatformUtil
import net.osmand.data.LatLon
import net.osmand.telegram.utils.AndroidUtils
import net.osmand.util.MapUtils
import java.util.*
import kotlin.math.atan2
class TelegramLocationProvider(private val app: TelegramApplication) : SensorEventListener {
private var lastTimeGPSLocationFixed: Long = 0
private var gpsSignalLost: Boolean = false
private var sensorRegistered = false
private val mGravs = FloatArray(3)
@ -45,31 +43,29 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
var lastKnownLocation: net.osmand.Location? = null
private set
val gpsInfo = GPSInfo()
private var fusedLocationProviderClient: FusedLocationProviderClient? = null
private val locationRequest = LocationRequest().apply {
interval = 1000
fastestInterval = 500
maxWaitTime = 2000
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
private val locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
super.onLocationResult(locationResult)
val lastLocation = locationResult?.lastLocation
if (lastLocation != null) {
lastTimeGPSLocationFixed = lastLocation.time
}
setLocation(convertLocation(lastLocation))
}
}
private val locationListeners = ArrayList<TelegramLocationListener>()
private val compassListeners = ArrayList<TelegramCompassListener>()
private var gpsStatusListener: GpsStatus.Listener? = null
private val mRotationM = FloatArray(9)
private var agpsDataLastTimeDownloaded: Long = 0
private val useMagneticFieldSensorCompass = false
private val gpsListener = object : LocationListener {
override fun onLocationChanged(location: Location?) {
if (location != null) {
lastTimeGPSLocationFixed = location.time
}
setLocation(convertLocation(location))
}
override fun onProviderDisabled(provider: String) {}
override fun onProviderEnabled(provider: String) {}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
}
private val networkListeners = LinkedList<LocationListener>()
val lastKnownLocationLatLon: LatLon?
get() = if (lastKnownLocation != null) {
LatLon(lastKnownLocation!!.latitude, lastKnownLocation!!.longitude)
@ -87,109 +83,20 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
@SuppressLint("MissingPermission")
fun resumeAllUpdates() {
val service = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (app.isInternetConnectionAvailable) {
if (System.currentTimeMillis() - agpsDataLastTimeDownloaded > AGPS_TO_REDOWNLOAD) {
//force an updated check for internet connectivity here before destroying A-GPS-data
if (app.isInternetConnectionAvailable(true)) {
//redownloadAGPS()
}
}
if (AndroidUtils.isLocationPermissionAvailable(app) && fusedLocationProviderClient == null) {
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(app)
}
if (AndroidUtils.isLocationPermissionAvailable(app)) {
service.addGpsStatusListener(getGpsStatusListener(service))
try {
service.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
GPS_TIMEOUT_REQUEST.toLong(),
GPS_DIST_REQUEST.toFloat(),
gpsListener
)
} catch (e: IllegalArgumentException) {
Log.d(PlatformUtil.TAG, "GPS location provider not available") //$NON-NLS-1$
}
// try to always ask for network provide : it is faster way to find location
val providers = service.getProviders(true) ?: return
for (provider in providers) {
if (provider == null || provider == LocationManager.GPS_PROVIDER) {
continue
}
try {
val networkListener = NetworkListener()
service.requestLocationUpdates(
provider,
GPS_TIMEOUT_REQUEST.toLong(),
GPS_DIST_REQUEST.toFloat(),
networkListener
)
networkListeners.add(networkListener)
} catch (e: IllegalArgumentException) {
Log.d(
PlatformUtil.TAG,
"$provider location provider not available"
) //$NON-NLS-1$
}
}
try {
fusedLocationProviderClient?.requestLocationUpdates(
locationRequest, locationCallback, Looper.myLooper())
} catch (unlikely: SecurityException) {
Log.d(PlatformUtil.TAG, "Lost location permissions. Couldn't request updates. $unlikely")
}
registerOrUnregisterCompassListener(true)
}
private fun redownloadAGPS() {
try {
val service = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
service.sendExtraCommand(LocationManager.GPS_PROVIDER, "delete_aiding_data", null)
val bundle = Bundle()
service.sendExtraCommand("gps", "force_xtra_injection", bundle)
service.sendExtraCommand("gps", "force_time_injection", bundle)
agpsDataLastTimeDownloaded = System.currentTimeMillis()
} catch (e: Exception) {
agpsDataLastTimeDownloaded = 0L
e.printStackTrace()
}
}
private fun getGpsStatusListener(service: LocationManager): GpsStatus.Listener {
gpsStatusListener = object : GpsStatus.Listener {
private var gpsStatus: GpsStatus? = null
@SuppressLint("MissingPermission")
override fun onGpsStatusChanged(event: Int) {
try {
gpsStatus = service.getGpsStatus(gpsStatus)
} catch (e: Exception) {
e.printStackTrace()
}
updateGPSInfo(gpsStatus)
updateLocation(lastKnownLocation)
}
}
return gpsStatusListener!!
}
private fun updateGPSInfo(s: GpsStatus?) {
var fixed = false
var n = 0
var u = 0
if (s != null) {
val iterator = s.satellites.iterator()
while (iterator.hasNext()) {
val g = iterator.next()
n++
if (g.usedInFix()) {
u++
fixed = true
}
}
}
gpsInfo.fixed = fixed
gpsInfo.foundSatellites = n
gpsInfo.usedSatellites = u
}
fun updateScreenOrientation(orientation: Int) {
currentScreenOrientation = orientation
}
@ -217,12 +124,12 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
@Synchronized
fun registerOrUnregisterCompassListener(register: Boolean) {
if (sensorRegistered && !register) {
Log.d(PlatformUtil.TAG, "Disable sensor") //$NON-NLS-1$
Log.d(PlatformUtil.TAG, "Disable sensor")
(app.getSystemService(Context.SENSOR_SERVICE) as SensorManager).unregisterListener(this)
sensorRegistered = false
heading = null
} else if (!sensorRegistered && register) {
Log.d(PlatformUtil.TAG, "Enable sensor") //$NON-NLS-1$
Log.d(PlatformUtil.TAG, "Enable sensor")
val sensorMgr = app.getSystemService(Context.SENSOR_SERVICE) as SensorManager
if (useMagneticFieldSensorCompass) {
var s: Sensor? = sensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
@ -360,7 +267,7 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
}
private fun getAngle(sinA: Float, cosA: Float) = MapUtils.unifyRotationTo360(
(Math.atan2(sinA.toDouble(), cosA.toDouble()) * 180 / Math.PI).toFloat()
(atan2(sinA.toDouble(), cosA.toDouble()) * 180 / Math.PI).toFloat()
)
private fun updateLocation(loc: net.osmand.Location?) {
@ -369,31 +276,11 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
}
}
private fun useOnlyGPS() =
System.currentTimeMillis() - lastTimeGPSLocationFixed < NOT_SWITCH_TO_NETWORK_WHEN_GPS_LOST_MS
// Working with location checkListeners
private inner class NetworkListener : LocationListener {
override fun onLocationChanged(location: Location) {
if (!useOnlyGPS()) {
setLocation(convertLocation(location))
}
}
override fun onProviderDisabled(provider: String) {}
override fun onProviderEnabled(provider: String) {}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
}
private fun stopLocationRequests() {
val service = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
service.removeGpsStatusListener(gpsStatusListener)
service.removeUpdates(gpsListener)
while (!networkListeners.isEmpty()) {
service.removeUpdates(networkListeners.poll())
try {
fusedLocationProviderClient?.removeLocationUpdates(locationCallback)
} catch (unlikely: SecurityException) {
Log.d(PlatformUtil.TAG, "Lost location permissions. Couldn't remove updates. $unlikely")
}
}
@ -403,17 +290,7 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
}
private fun setLocation(location: net.osmand.Location?) {
if (location == null) {
updateGPSInfo(null)
}
if (location != null) {
if (gpsSignalLost) {
gpsSignalLost = false
}
}
this.lastKnownLocation = location
// Update information
updateLocation(this.lastKnownLocation)
}
@ -424,21 +301,10 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
}
}
class GPSInfo {
var foundSatellites = 0
var usedSatellites = 0
var fixed = false
}
companion object {
private const val INTERVAL_TO_CLEAR_SET_LOCATION = 30 * 1000
private const val GPS_TIMEOUT_REQUEST = 0
private const val GPS_DIST_REQUEST = 0
private const val NOT_SWITCH_TO_NETWORK_WHEN_GPS_LOST_MS = 12000
private const val AGPS_TO_REDOWNLOAD = 16L * 60 * 60 * 1000 // 16 hours
fun convertLocation(l: Location?): net.osmand.Location? {
if (l == null) {
return null

View file

@ -4,30 +4,27 @@ import android.annotation.SuppressLint
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.ServiceInfo
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.*
import android.util.Log
import android.widget.Toast
import com.google.android.gms.location.*
import net.osmand.PlatformUtil
import net.osmand.telegram.TelegramSettings.ShareChatInfo
import net.osmand.telegram.helpers.TelegramHelper
import net.osmand.telegram.helpers.TelegramHelper.*
import net.osmand.telegram.helpers.TelegramHelper.TelegramIncomingMessagesListener
import net.osmand.telegram.helpers.TelegramHelper.TelegramOutgoingMessagesListener
import net.osmand.telegram.notifications.TelegramNotification.NotificationType
import net.osmand.telegram.utils.AndroidUtils
import org.drinkless.td.libcore.telegram.TdApi
import java.util.*
private const val UPDATE_WIDGET_INTERVAL_MS = 1000L // 1 sec
private const val UPDATE_LIVE_MESSAGES_INTERVAL_MS = 10000L // 10 sec
private const val UPDATE_LIVE_TRACKS_INTERVAL_MS = 30000L // 30 sec
class TelegramService : Service(), LocationListener, TelegramIncomingMessagesListener,
class TelegramService : Service(), TelegramIncomingMessagesListener,
TelegramOutgoingMessagesListener {
private val log = PlatformUtil.getLog(TelegramService::class.java)
private fun app() = application as TelegramApplication
private val binder = LocationServiceBinder()
private var shouldCleanupResources: Boolean = false
@ -41,10 +38,18 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
private var updateWidgetHandler: Handler? = null
private var updateWidgetThread = HandlerThread("WidgetUpdateServiceThread")
// FusedLocationProviderClient - Main class for receiving location updates.
private lateinit var fusedLocationProviderClient: FusedLocationProviderClient
// LocationRequest - Requirements for the location updates, i.e., how often you should receive
// updates, the priority, etc.
private lateinit var locationRequest: LocationRequest
// LocationCallback - Called when FusedLocationProviderClient has a new Location.
private lateinit var locationCallback: LocationCallback
var usedBy = 0
private set
var serviceOffProvider: String = LocationManager.GPS_PROVIDER
private set
var sendLocationInterval = 0L
private set
@ -60,6 +65,42 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
updateShareInfoHandler = Handler(mHandlerThread.looper)
updateTracksHandler = Handler(tracksHandlerThread.looper)
updateWidgetHandler = Handler(updateWidgetThread.looper)
fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this)
locationRequest = LocationRequest().apply {
// Sets the desired interval for active location updates. This interval is inexact. You
// may not receive updates at all if no location sources are available, or you may
// receive them less frequently than requested. You may also receive updates more
// frequently than requested if other applications are requesting location at a more
// frequent interval.
//
// IMPORTANT NOTE: Apps running on Android 8.0 and higher devices (regardless of
// targetSdkVersion) may receive updates less frequently than this interval when the app
// is no longer in the foreground.
interval = 1000
// Sets the fastest rate for active location updates. This interval is exact, and your
// application will never receive updates more frequently than this value.
fastestInterval = 500
// Sets the maximum time when batched location updates are delivered. Updates may be
// delivered sooner than this interval.
maxWaitTime = 2000
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
super.onLocationResult(locationResult)
val location = convertLocation(locationResult?.lastLocation)
if (System.currentTimeMillis() - lastLocationSentTime > sendLocationInterval * 1000) {
lastLocationSentTime = System.currentTimeMillis()
app().shareLocationHelper.updateLocation(location)
}
}
}
}
override fun onBind(intent: Intent): IBinder {
@ -144,27 +185,27 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
}
fun forceLocationUpdate() {
val location = getFirstTimeRunDefaultLocation()
app().shareLocationHelper.updateLocation(location)
getFirstTimeRunDefaultLocation { location ->
app().shareLocationHelper.updateLocation(location)
}
}
private fun initLocationUpdates() {
val firstLocation = getFirstTimeRunDefaultLocation()
app().shareLocationHelper.updateLocation(firstLocation)
getFirstTimeRunDefaultLocation { location ->
app().shareLocationHelper.updateLocation(location)
}
// request location updates
/*
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
try {
locationManager.requestLocationUpdates(serviceOffProvider, 0, 0f, this@TelegramService)
} catch (e: SecurityException) {
fusedLocationProviderClient.requestLocationUpdates(
locationRequest, locationCallback, Looper.myLooper())
} catch (unlikely: SecurityException) {
Toast.makeText(this, R.string.no_location_permission, Toast.LENGTH_LONG).show()
log.debug("Location service permission not granted")
Log.d(PlatformUtil.TAG, "Lost location permissions. Couldn't request updates. $unlikely")
} catch (e: IllegalArgumentException) {
Toast.makeText(this, R.string.gps_not_available, Toast.LENGTH_LONG).show()
log.debug("GPS location provider not available")
Log.d(PlatformUtil.TAG, "GPS location provider not available")
}
*/
}
private fun startShareInfoUpdates() {
@ -219,62 +260,27 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
}
@SuppressLint("MissingPermission")
private fun getFirstTimeRunDefaultLocation(): net.osmand.Location? {
private fun getFirstTimeRunDefaultLocation(locationListener: (net.osmand.Location?) -> Unit) {
val app = app()
if (!AndroidUtils.isLocationPermissionAvailable(app)) {
return null
locationListener(null)
return
}
var location: net.osmand.Location? = null
/*
val service = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val ps = service.getProviders(true) ?: return null
val providers = ArrayList(ps)
// note, passive provider is from API_LEVEL 8 but it is a constant, we can check for it.
// constant should not be changed in future
val passiveFirst = providers.indexOf("passive") // LocationManager.PASSIVE_PROVIDER
// put passive provider to first place
if (passiveFirst > -1) {
providers.add(0, providers.removeAt(passiveFirst))
}
// find location
for (provider in providers) {
val loc = convertLocation(service.getLastKnownLocation(provider))
if (loc != null && (location == null || loc.hasAccuracy() && loc.accuracy < location.accuracy)) {
location = loc
}
}
*/
return location
fusedLocationProviderClient.lastLocation
.addOnSuccessListener { location : Location? ->
locationListener(convertLocation(location))
}
}
private fun removeLocationUpdates() {
// remove updates
/*
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
try {
locationManager.removeUpdates(this)
} catch (e: SecurityException) {
log.debug("Location service permission not granted")
}
*/
}
override fun onLocationChanged(l: Location?) {
val location = convertLocation(l)
if (System.currentTimeMillis() - lastLocationSentTime > sendLocationInterval * 1000) {
lastLocationSentTime = System.currentTimeMillis()
app().shareLocationHelper.updateLocation(location)
fusedLocationProviderClient.removeLocationUpdates(locationCallback)
} catch (unlikely: SecurityException) {
Log.d(PlatformUtil.TAG, "Lost location permissions. Couldn't remove updates. $unlikely")
}
}
override fun onProviderDisabled(provider: String) {
Toast.makeText(this, getString(R.string.location_service_no_gps_available), Toast.LENGTH_LONG).show()
}
override fun onProviderEnabled(provider: String) {}
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
override fun onTaskRemoved(rootIntent: Intent) {
val app = app()
if (app.telegramService != null) {
@ -316,7 +322,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
}
override fun onSendLiveLocationError(code: Int, message: String, shareInfo: ShareChatInfo, messageType: Int) {
log.debug("Send live location error: $code - $message")
Log.d(PlatformUtil.TAG, "Send live location error: $code - $message")
when (messageType) {
TelegramHelper.MESSAGE_TYPE_TEXT -> shareInfo.pendingTdLibText--
TelegramHelper.MESSAGE_TYPE_MAP -> {

View file

@ -1,7 +1,6 @@
package net.osmand.telegram
import android.content.Context
import android.location.LocationManager
import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import androidx.annotation.ColorRes