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

View file

@ -4,8 +4,8 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android-extensions'
android { android {
compileSdkVersion 28 compileSdkVersion 29
buildToolsVersion "28.0.3" buildToolsVersion "29.0.3"
sourceSets { sourceSets {
main { main {
@ -23,7 +23,7 @@ android {
defaultConfig { defaultConfig {
applicationId "net.osmand.telegram" applicationId "net.osmand.telegram"
minSdkVersion 15 minSdkVersion 15
targetSdkVersion 28 targetSdkVersion 29
multiDexEnabled true multiDexEnabled true
versionCode 1 versionCode 1
versionCode System.getenv("APK_NUMBER_VERSION") ? System.getenv("APK_NUMBER_VERSION").toInteger() : versionCode 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.net.NetworkInfo
import android.os.Build import android.os.Build
import android.os.Handler import android.os.Handler
import androidx.core.content.ContextCompat
import net.osmand.PlatformUtil import net.osmand.PlatformUtil
import net.osmand.telegram.ui.TrackerLogcatActivity
import net.osmand.telegram.helpers.* import net.osmand.telegram.helpers.*
import net.osmand.telegram.helpers.OsmandAidlHelper.OsmandHelperListener import net.osmand.telegram.helpers.OsmandAidlHelper.OsmandHelperListener
import net.osmand.telegram.helpers.OsmandAidlHelper.UpdatesListener import net.osmand.telegram.helpers.OsmandAidlHelper.UpdatesListener
import net.osmand.telegram.notifications.NotificationHelper import net.osmand.telegram.notifications.NotificationHelper
import net.osmand.telegram.ui.TrackerLogcatActivity
import net.osmand.telegram.utils.AndroidUtils import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.UiUtils import net.osmand.telegram.utils.UiUtils
import java.io.File import java.io.File
@ -146,35 +147,21 @@ class TelegramApplication : Application() {
return internetConnectionAvailable return internetConnectionAvailable
} }
private fun startTelegramService(intent: Int, serviceOffInterval: Long = 0) { private fun startTelegramService(intent: Int) {
var i = intent var i = intent
var interval = serviceOffInterval
val serviceIntent = Intent(this, TelegramService::class.java) val serviceIntent = Intent(this, TelegramService::class.java)
val telegramService = telegramService val telegramService = telegramService
if (telegramService != null) { if (telegramService != null) {
i = intent or telegramService.usedBy i = intent or telegramService.usedBy
interval = if (TelegramService.isOffIntervalDepended(intent)) {
Math.min(telegramService.serviceOffInterval, interval)
} else {
telegramService.serviceOffInterval
}
telegramService.stopSelf() telegramService.stopSelf()
} }
serviceIntent.putExtra(TelegramService.USAGE_INTENT, i) serviceIntent.putExtra(TelegramService.USAGE_INTENT, i)
serviceIntent.putExtra(TelegramService.USAGE_OFF_INTERVAL, interval)
serviceIntent.putExtra(TelegramService.SEND_LOCATION_INTERVAL, settings.sendMyLocInterval) serviceIntent.putExtra(TelegramService.SEND_LOCATION_INTERVAL, settings.sendMyLocInterval)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ContextCompat.startForegroundService(this, serviceIntent)
startForegroundService(serviceIntent)
} else {
startService(serviceIntent)
}
} }
fun startMyLocationService() { fun startMyLocationService() {
val interval = settings.sendMyLocInterval startTelegramService(TelegramService.USED_BY_MY_LOCATION)
startTelegramService(TelegramService.USED_BY_MY_LOCATION, TelegramService.normalizeOffInterval(interval))
} }
fun stopMyLocationService() { fun stopMyLocationService() {

View file

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

View file

@ -1,16 +1,14 @@
package net.osmand.telegram package net.osmand.telegram
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.AlarmManager
import android.app.PendingIntent
import android.app.Service import android.app.Service
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.ServiceInfo
import android.location.Location import android.location.Location
import android.location.LocationListener import android.location.LocationListener
import android.location.LocationManager import android.location.LocationManager
import android.os.* import android.os.*
import android.util.Log
import android.widget.Toast import android.widget.Toast
import net.osmand.PlatformUtil import net.osmand.PlatformUtil
import net.osmand.telegram.TelegramSettings.ShareChatInfo 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 private const val UPDATE_LIVE_TRACKS_INTERVAL_MS = 30000L // 30 sec
class TelegramService : Service(), LocationListener, TelegramIncomingMessagesListener, class TelegramService : Service(), LocationListener, TelegramIncomingMessagesListener,
TelegramOutgoingMessagesListener { TelegramOutgoingMessagesListener {
private val log = PlatformUtil.getLog(TelegramService::class.java) private val log = PlatformUtil.getLog(TelegramService::class.java)
@ -43,21 +41,14 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
private var updateWidgetHandler: Handler? = null private var updateWidgetHandler: Handler? = null
private var updateWidgetThread = HandlerThread("WidgetUpdateServiceThread") private var updateWidgetThread = HandlerThread("WidgetUpdateServiceThread")
var handler: Handler? = null
private set
var usedBy = 0 var usedBy = 0
private set private set
var serviceOffProvider: String = LocationManager.GPS_PROVIDER var serviceOffProvider: String = LocationManager.GPS_PROVIDER
private set private set
var serviceOffInterval = 0L
private set
var serviceErrorInterval = 0L
private set
var sendLocationInterval = 0L var sendLocationInterval = 0L
private set private set
private var lastLocationSentTime = 0L private var lastLocationSentTime = 0L
private var pendingIntent: PendingIntent? = null
class LocationServiceBinder : Binder() class LocationServiceBinder : Binder()
@ -71,7 +62,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
updateWidgetHandler = Handler(updateWidgetThread.looper) updateWidgetHandler = Handler(updateWidgetThread.looper)
} }
override fun onBind(intent: Intent): IBinder? { override fun onBind(intent: Intent): IBinder {
return binder return binder
} }
@ -86,13 +77,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
ctx.stopService(serviceIntent) ctx.stopService(serviceIntent)
} }
isUsedByMyLocation(usedBy) -> { isUsedByMyLocation(usedBy) -> {
val app = app() app().notificationHelper.refreshNotification(NotificationType.LOCATION)
if (app.settings.sendMyLocInterval >= OFF_INTERVAL_THRESHOLD && serviceOffInterval == 0L) {
serviceOffInterval = app.settings.sendMyLocInterval
setupServiceErrorInterval()
setupAlarm()
}
app.notificationHelper.refreshNotification(NotificationType.LOCATION)
} }
isUsedByUsersLocations(usedBy) -> removeLocationUpdates() isUsedByUsersLocations(usedBy) -> removeLocationUpdates()
} }
@ -100,19 +85,21 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
val app = app() val app = app()
handler = Handler()
val usageIntent = intent.getIntExtra(USAGE_INTENT, 0) val usageIntent = intent.getIntExtra(USAGE_INTENT, 0)
usedBy = usageIntent or usedBy usedBy = usageIntent or usedBy
serviceOffInterval = intent.getLongExtra(USAGE_OFF_INTERVAL, 0)
sendLocationInterval = intent.getLongExtra(SEND_LOCATION_INTERVAL, 0) sendLocationInterval = intent.getLongExtra(SEND_LOCATION_INTERVAL, 0)
setupServiceErrorInterval()
app.telegramHelper.addIncomingMessagesListener(this) app.telegramHelper.addIncomingMessagesListener(this)
app.telegramHelper.addOutgoingMessagesListener(this) app.telegramHelper.addOutgoingMessagesListener(this)
app.telegramService = 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)) { if (isUsedByMyLocation(usedBy)) {
initLocationUpdates() initLocationUpdates()
startShareInfoUpdates() startShareInfoUpdates()
@ -124,21 +111,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
} }
app.shareLocationHelper.checkAndSendBufferMessages() app.shareLocationHelper.checkAndSendBufferMessages()
val locationNotification = app.notificationHelper.locationNotification return START_REDELIVER_INTENT
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)
} }
override fun onDestroy() { override fun onDestroy() {
@ -158,13 +131,6 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
removeLocationUpdates() removeLocationUpdates()
if (!isContinuous()) {
val lock = getLock(this)
if (lock.isHeld) {
lock.release()
}
}
if (shouldCleanupResources) { if (shouldCleanupResources) {
app.cleanupResources() app.cleanupResources()
} }
@ -176,7 +142,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
fun updateSendLocationInterval(newInterval: Long) { fun updateSendLocationInterval(newInterval: Long) {
sendLocationInterval = newInterval sendLocationInterval = newInterval
} }
fun forceLocationUpdate() { fun forceLocationUpdate() {
val location = getFirstTimeRunDefaultLocation() val location = getFirstTimeRunDefaultLocation()
app().shareLocationHelper.updateLocation(location) app().shareLocationHelper.updateLocation(location)
@ -186,21 +152,16 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
val firstLocation = getFirstTimeRunDefaultLocation() val firstLocation = getFirstTimeRunDefaultLocation()
app().shareLocationHelper.updateLocation(firstLocation) app().shareLocationHelper.updateLocation(firstLocation)
// requesting // request location updates
if (isContinuous()) { val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
// request location updates try {
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager locationManager.requestLocationUpdates(serviceOffProvider, 0, 0f, this@TelegramService)
try { } catch (e: SecurityException) {
locationManager.requestLocationUpdates(serviceOffProvider, 0, 0f, this@TelegramService) Toast.makeText(this, R.string.no_location_permission, Toast.LENGTH_LONG).show()
} catch (e: SecurityException) { log.debug("Location service permission not granted")
Toast.makeText(this, R.string.no_location_permission, Toast.LENGTH_LONG).show() } catch (e: IllegalArgumentException) {
Log.d(PlatformUtil.TAG, "Location service permission not granted") //$NON-NLS-1$ Toast.makeText(this, R.string.gps_not_available, Toast.LENGTH_LONG).show()
} catch (e: IllegalArgumentException) { log.debug("GPS location provider not available")
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()
} }
} }
@ -254,7 +215,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
startWidgetUpdates() startWidgetUpdates()
}, UPDATE_WIDGET_INTERVAL_MS) }, UPDATE_WIDGET_INTERVAL_MS)
} }
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
private fun getFirstTimeRunDefaultLocation(): net.osmand.Location? { private fun getFirstTimeRunDefaultLocation(): net.osmand.Location? {
val app = app() val app = app()
@ -282,43 +243,19 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
return location 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() { private fun removeLocationUpdates() {
// remove updates // remove updates
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
try { try {
locationManager.removeUpdates(this) locationManager.removeUpdates(this)
} catch (e: SecurityException) { } 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?) { override fun onLocationChanged(l: Location?) {
val location = convertLocation(l) val location = convertLocation(l)
if (!isContinuous()) { if (System.currentTimeMillis() - lastLocationSentTime > sendLocationInterval * 1000) {
// 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) {
lastLocationSentTime = System.currentTimeMillis() lastLocationSentTime = System.currentTimeMillis()
app().shareLocationHelper.updateLocation(location) app().shareLocationHelper.updateLocation(location)
} }
@ -373,7 +310,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
} }
override fun onSendLiveLocationError(code: Int, message: String, shareInfo: ShareChatInfo, messageType: Int) { 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) { when (messageType) {
TelegramHelper.MESSAGE_TYPE_TEXT -> shareInfo.pendingTdLibText-- TelegramHelper.MESSAGE_TYPE_TEXT -> shareInfo.pendingTdLibText--
TelegramHelper.MESSAGE_TYPE_MAP -> { 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_MY_LOCATION: Int = 1
const val USED_BY_USERS_LOCATIONS: Int = 2 const val USED_BY_USERS_LOCATIONS: Int = 2
const val USAGE_INTENT = "SERVICE_USED_BY" 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 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 { fun isUsedByMyLocation(usedBy: Int): Boolean {
return (usedBy and USED_BY_MY_LOCATION) > 0 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 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? { fun convertLocation(l: Location?): net.osmand.Location? {
if (l == null) { if (l == null) {
return null return null

View file

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