Fix tracker backgound location issue

This commit is contained in:
max-klaus 2021-01-11 20:04:51 +03:00
parent b9f1f69934
commit 9c7bacc3af
7 changed files with 41 additions and 184 deletions

View file

@ -19,7 +19,10 @@
android:launchMode="singleTask"
android:screenOrientation="unspecified"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:hasFragileUserData="true"
android:requestLegacyExternalStorage="true">
<activity android:name=".ui.TrackerLogcatActivity" />
<activity
android:name=".ui.MainActivity"
@ -48,14 +51,13 @@
<service
android:name=".TelegramService"
android:label="@string/process_service"
android:foregroundServiceType="location"
android:stopWithTask="false">
<intent-filter>
<action android:name="net.osmand.telegram.TelegramService" />
</intent-filter>
</service>
<receiver android:name=".OnTelegramServiceAlarmReceiver" />
<receiver
android:name=".InitAppBroadcastReceiver"
android:enabled="true"

View file

@ -4,8 +4,8 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 28
buildToolsVersion "28.0.3"
compileSdkVersion 29
buildToolsVersion "29.0.3"
sourceSets {
main {
@ -23,7 +23,7 @@ android {
defaultConfig {
applicationId "net.osmand.telegram"
minSdkVersion 15
targetSdkVersion 28
targetSdkVersion 29
multiDexEnabled true
versionCode 1
versionCode System.getenv("APK_NUMBER_VERSION") ? System.getenv("APK_NUMBER_VERSION").toInteger() : versionCode

View file

@ -1,42 +0,0 @@
package net.osmand.telegram
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.location.LocationManager
import net.osmand.telegram.utils.AndroidUtils
class OnTelegramServiceAlarmReceiver : BroadcastReceiver() {
@SuppressLint("MissingPermission")
override fun onReceive(context: Context, intent: Intent) {
val lock = TelegramService.getLock(context)
val app = context.applicationContext as TelegramApplication
val service = app.telegramService
// do not do nothing
if (lock.isHeld || service == null) {
return
}
lock.acquire(15 * 60 * 1000L)
// request location updates
val locationManager = service.getSystemService(Context.LOCATION_SERVICE) as LocationManager
try {
if (AndroidUtils.isLocationPermissionAvailable(app)) {
locationManager.requestLocationUpdates(service.serviceOffProvider, 0, 0f, service)
}
val handler = service.handler
if (service.serviceOffInterval > service.serviceErrorInterval && handler != null) {
handler.postDelayed({
// if lock is not anymore held
if (lock.isHeld) {
lock.release()
locationManager.removeUpdates(service)
}
}, service.serviceErrorInterval)
}
} catch (e: RuntimeException) {
e.printStackTrace()
}
}
}

View file

@ -8,12 +8,13 @@ import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.os.Build
import android.os.Handler
import androidx.core.content.ContextCompat
import net.osmand.PlatformUtil
import net.osmand.telegram.ui.TrackerLogcatActivity
import net.osmand.telegram.helpers.*
import net.osmand.telegram.helpers.OsmandAidlHelper.OsmandHelperListener
import net.osmand.telegram.helpers.OsmandAidlHelper.UpdatesListener
import net.osmand.telegram.notifications.NotificationHelper
import net.osmand.telegram.ui.TrackerLogcatActivity
import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.UiUtils
import java.io.File
@ -146,35 +147,21 @@ class TelegramApplication : Application() {
return internetConnectionAvailable
}
private fun startTelegramService(intent: Int, serviceOffInterval: Long = 0) {
private fun startTelegramService(intent: Int) {
var i = intent
var interval = serviceOffInterval
val serviceIntent = Intent(this, TelegramService::class.java)
val telegramService = telegramService
if (telegramService != null) {
i = intent or telegramService.usedBy
interval = if (TelegramService.isOffIntervalDepended(intent)) {
Math.min(telegramService.serviceOffInterval, interval)
} else {
telegramService.serviceOffInterval
}
telegramService.stopSelf()
}
serviceIntent.putExtra(TelegramService.USAGE_INTENT, i)
serviceIntent.putExtra(TelegramService.USAGE_OFF_INTERVAL, interval)
serviceIntent.putExtra(TelegramService.SEND_LOCATION_INTERVAL, settings.sendMyLocInterval)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent)
} else {
startService(serviceIntent)
}
ContextCompat.startForegroundService(this, serviceIntent)
}
fun startMyLocationService() {
val interval = settings.sendMyLocInterval
startTelegramService(TelegramService.USED_BY_MY_LOCATION, TelegramService.normalizeOffInterval(interval))
startTelegramService(TelegramService.USED_BY_MY_LOCATION)
}
fun stopMyLocationService() {

View file

@ -166,7 +166,7 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
registerOrUnregisterCompassListener(true)
}
fun redownloadAGPS() {
private fun redownloadAGPS() {
try {
val service = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
service.sendExtraCommand(LocationManager.GPS_PROVIDER, "delete_aiding_data", null)

View file

@ -1,16 +1,14 @@
package net.osmand.telegram
import android.annotation.SuppressLint
import android.app.AlarmManager
import android.app.PendingIntent
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 net.osmand.PlatformUtil
import net.osmand.telegram.TelegramSettings.ShareChatInfo
@ -26,7 +24,7 @@ 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,
TelegramOutgoingMessagesListener {
TelegramOutgoingMessagesListener {
private val log = PlatformUtil.getLog(TelegramService::class.java)
@ -43,21 +41,14 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
private var updateWidgetHandler: Handler? = null
private var updateWidgetThread = HandlerThread("WidgetUpdateServiceThread")
var handler: Handler? = null
private set
var usedBy = 0
private set
var serviceOffProvider: String = LocationManager.GPS_PROVIDER
private set
var serviceOffInterval = 0L
private set
var serviceErrorInterval = 0L
private set
var sendLocationInterval = 0L
private set
private var lastLocationSentTime = 0L
private var pendingIntent: PendingIntent? = null
class LocationServiceBinder : Binder()
@ -71,7 +62,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
updateWidgetHandler = Handler(updateWidgetThread.looper)
}
override fun onBind(intent: Intent): IBinder? {
override fun onBind(intent: Intent): IBinder {
return binder
}
@ -86,13 +77,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
ctx.stopService(serviceIntent)
}
isUsedByMyLocation(usedBy) -> {
val app = app()
if (app.settings.sendMyLocInterval >= OFF_INTERVAL_THRESHOLD && serviceOffInterval == 0L) {
serviceOffInterval = app.settings.sendMyLocInterval
setupServiceErrorInterval()
setupAlarm()
}
app.notificationHelper.refreshNotification(NotificationType.LOCATION)
app().notificationHelper.refreshNotification(NotificationType.LOCATION)
}
isUsedByUsersLocations(usedBy) -> removeLocationUpdates()
}
@ -100,19 +85,21 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
val app = app()
handler = Handler()
val usageIntent = intent.getIntExtra(USAGE_INTENT, 0)
usedBy = usageIntent or usedBy
serviceOffInterval = intent.getLongExtra(USAGE_OFF_INTERVAL, 0)
sendLocationInterval = intent.getLongExtra(SEND_LOCATION_INTERVAL, 0)
setupServiceErrorInterval()
app.telegramHelper.addIncomingMessagesListener(this)
app.telegramHelper.addOutgoingMessagesListener(this)
app.telegramService = this
val locationNotification = app.notificationHelper.locationNotification
val notification = app.notificationHelper.buildNotification(locationNotification)
startForeground(locationNotification.telegramNotificationId, notification)
app.notificationHelper.refreshNotification(locationNotification.type)
if (isUsedByMyLocation(usedBy)) {
initLocationUpdates()
startShareInfoUpdates()
@ -124,21 +111,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
}
app.shareLocationHelper.checkAndSendBufferMessages()
val locationNotification = app.notificationHelper.locationNotification
val notification = app.notificationHelper.buildNotification(locationNotification)
startForeground(locationNotification.telegramNotificationId, notification)
app.notificationHelper.refreshNotification(locationNotification.type)
return Service.START_REDELIVER_INTENT
}
private fun setupServiceErrorInterval() {
serviceErrorInterval = serviceOffInterval / 5
// 1. not more than 12 mins
serviceErrorInterval = Math.min(serviceErrorInterval, 12 * 60 * 1000)
// 2. not less than 30 seconds
serviceErrorInterval = Math.max(serviceErrorInterval, 30 * 1000)
// 3. not more than serviceOffInterval
serviceErrorInterval = Math.min(serviceErrorInterval, serviceOffInterval)
return START_REDELIVER_INTENT
}
override fun onDestroy() {
@ -158,13 +131,6 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
removeLocationUpdates()
if (!isContinuous()) {
val lock = getLock(this)
if (lock.isHeld) {
lock.release()
}
}
if (shouldCleanupResources) {
app.cleanupResources()
}
@ -186,21 +152,16 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
val firstLocation = getFirstTimeRunDefaultLocation()
app().shareLocationHelper.updateLocation(firstLocation)
// requesting
if (isContinuous()) {
// request location updates
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
try {
locationManager.requestLocationUpdates(serviceOffProvider, 0, 0f, this@TelegramService)
} catch (e: SecurityException) {
Toast.makeText(this, R.string.no_location_permission, Toast.LENGTH_LONG).show()
Log.d(PlatformUtil.TAG, "Location service permission not granted") //$NON-NLS-1$
} catch (e: IllegalArgumentException) {
Toast.makeText(this, R.string.gps_not_available, Toast.LENGTH_LONG).show()
Log.d(PlatformUtil.TAG, "GPS location provider not available") //$NON-NLS-1$
}
} else {
setupAlarm()
// request location updates
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
try {
locationManager.requestLocationUpdates(serviceOffProvider, 0, 0f, this@TelegramService)
} catch (e: SecurityException) {
Toast.makeText(this, R.string.no_location_permission, Toast.LENGTH_LONG).show()
log.debug("Location service permission not granted")
} catch (e: IllegalArgumentException) {
Toast.makeText(this, R.string.gps_not_available, Toast.LENGTH_LONG).show()
log.debug("GPS location provider not available")
}
}
@ -282,43 +243,19 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
return location
}
private fun setupAlarm() {
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
pendingIntent = PendingIntent.getBroadcast(this, 0, Intent(this, OnTelegramServiceAlarmReceiver::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 500, serviceOffInterval, pendingIntent)
}
private fun removeLocationUpdates() {
// remove updates
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
try {
locationManager.removeUpdates(this)
} catch (e: SecurityException) {
Log.d(PlatformUtil.TAG, "Location service permission not granted")
log.debug("Location service permission not granted")
}
}
private fun isContinuous(): Boolean {
return serviceOffInterval == 0L
}
override fun onLocationChanged(l: Location?) {
val location = convertLocation(l)
if (!isContinuous()) {
// unregister listener and wait next time
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
try {
locationManager.removeUpdates(this)
} catch (e: Throwable) {
Log.d(PlatformUtil.TAG, "Location service permission not granted") //$NON-NLS-1$
}
val lock = getLock(this)
if (lock.isHeld) {
lock.release()
}
app().shareLocationHelper.updateLocation(location)
} else if (System.currentTimeMillis() - lastLocationSentTime > sendLocationInterval * 1000) {
if (System.currentTimeMillis() - lastLocationSentTime > sendLocationInterval * 1000) {
lastLocationSentTime = System.currentTimeMillis()
app().shareLocationHelper.updateLocation(location)
}
@ -373,7 +310,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
}
override fun onSendLiveLocationError(code: Int, message: String, shareInfo: ShareChatInfo, messageType: Int) {
Log.d(PlatformUtil.TAG, "Send live location error: $code - $message")
log.debug("Send live location error: $code - $message")
when (messageType) {
TelegramHelper.MESSAGE_TYPE_TEXT -> shareInfo.pendingTdLibText--
TelegramHelper.MESSAGE_TYPE_MAP -> {
@ -388,26 +325,8 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
const val USED_BY_MY_LOCATION: Int = 1
const val USED_BY_USERS_LOCATIONS: Int = 2
const val USAGE_INTENT = "SERVICE_USED_BY"
const val USAGE_OFF_INTERVAL = "SERVICE_OFF_INTERVAL"
const val SEND_LOCATION_INTERVAL = "SEND_LOCATION_INTERVAL"
const val OFF_INTERVAL_THRESHOLD: Long = 30000L
private var lockStatic: PowerManager.WakeLock? = null
@Synchronized
fun getLock(context: Context): PowerManager.WakeLock {
var lockStatic = lockStatic
return if (lockStatic == null) {
val mgr = context.getSystemService(Context.POWER_SERVICE) as PowerManager
lockStatic = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "OsmandServiceLock")
this.lockStatic = lockStatic
lockStatic
} else {
lockStatic
}
}
fun isUsedByMyLocation(usedBy: Int): Boolean {
return (usedBy and USED_BY_MY_LOCATION) > 0
}
@ -416,14 +335,6 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
return (usedBy and USED_BY_USERS_LOCATIONS) > 0
}
fun isOffIntervalDepended(usedBy: Int): Boolean {
return isUsedByMyLocation(usedBy)
}
fun normalizeOffInterval(interval: Long): Long {
return if (interval < OFF_INTERVAL_THRESHOLD) 0 else interval
}
fun convertLocation(l: Location?): net.osmand.Location? {
if (l == null) {
return null

View file

@ -21,7 +21,6 @@ import android.widget.*
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.appbar.AppBarLayout
import net.osmand.PlatformUtil
import net.osmand.telegram.*
@ -42,7 +41,7 @@ private const val SUGGESTED = 2
private const val SHARE_LOCATION_CHAT = 1
private const val DEFAULT_CHAT = 0
private const val ADAPTER_UPDATE_INTERVAL_MIL = 5 * 1000L // 5 sec
private const val ADAPTER_UPDATE_INTERVAL_MS = 5 * 1000L // 5 sec
class MyLocationTabFragment : Fragment(), TelegramListener {
@ -380,7 +379,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
updateContent()
startHandler()
}
}, ADAPTER_UPDATE_INTERVAL_MIL)
}, ADAPTER_UPDATE_INTERVAL_MS)
}
private fun animateStartSharingBtn(show: Boolean) {