Telegram - added service for showing locations on map

This commit is contained in:
crimean 2018-06-11 13:41:43 +03:00
parent 2ab3abd502
commit 08c65712a4
10 changed files with 385 additions and 72 deletions

View file

@ -20,8 +20,8 @@
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:launchMode="singleTask"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
@ -33,14 +33,24 @@
</activity> </activity>
<service <service
android:name=".services.MyLocationService"
android:label="@string/process_location_service" android:label="@string/process_location_service"
android:name="net.osmand.telegram.LocationService" android:stopWithTask="false">
android:stopWithTask="true">
<intent-filter> <intent-filter>
<action android:name="net.osmand.telegram.LocationService" /> <action android:name="net.osmand.telegram.services.MyLocationService" />
</intent-filter> </intent-filter>
</service> </service>
<service
android:name=".services.UserLocationService"
android:label="@string/process_location_service"
android:stopWithTask="false">
<intent-filter>
<action android:name="net.osmand.telegram.services.UserLocationService" />
</intent-filter>
</service>
<receiver android:name=".notifications.NotificationDismissReceiver" /> <receiver android:name=".notifications.NotificationDismissReceiver" />
</application> </application>

View file

@ -44,6 +44,7 @@ class MainActivity : AppCompatActivity(), TelegramListener {
get() = application as TelegramApplication get() = application as TelegramApplication
private val telegramHelper get() = app.telegramHelper private val telegramHelper get() = app.telegramHelper
private val osmandHelper get() = app.osmandHelper
private val settings get() = app.settings private val settings get() = app.settings
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -92,7 +93,7 @@ class MainActivity : AppCompatActivity(), TelegramListener {
if (settings.hasAnyChatToShareLocation() && !AndroidUtils.isLocationPermissionAvailable(this)) { if (settings.hasAnyChatToShareLocation() && !AndroidUtils.isLocationPermissionAvailable(this)) {
requestLocationPermission() requestLocationPermission()
} else if (settings.hasAnyChatToShowOnMap() && !app.osmandHelper.isOsmandBound()) { } else if (settings.hasAnyChatToShowOnMap() && osmandHelper.initialized && !osmandHelper.isOsmandBound()) {
showOsmandMissingDialog() showOsmandMissingDialog()
} }
} }
@ -292,7 +293,7 @@ class MainActivity : AppCompatActivity(), TelegramListener {
app.shareLocationHelper.startSharingLocation() app.shareLocationHelper.startSharingLocation()
} }
} }
if (settings.hasAnyChatToShowOnMap() && app.osmandHelper.isOsmandBound()) { if (settings.hasAnyChatToShowOnMap() && osmandHelper.initialized && !osmandHelper.isOsmandBound()) {
showOsmandMissingDialog() showOsmandMissingDialog()
} }
} }
@ -362,18 +363,26 @@ class MainActivity : AppCompatActivity(), TelegramListener {
holder.showOnMapSwitch?.setOnCheckedChangeListener(null) holder.showOnMapSwitch?.setOnCheckedChangeListener(null)
holder.showOnMapSwitch?.isChecked = settings.isShowingChatOnMap(chatTitle) holder.showOnMapSwitch?.isChecked = settings.isShowingChatOnMap(chatTitle)
holder.showOnMapSwitch?.setOnCheckedChangeListener { view, isChecked -> holder.showOnMapSwitch?.setOnCheckedChangeListener { _, isChecked ->
settings.showChatOnMap(chatTitle, isChecked) settings.showChatOnMap(chatTitle, isChecked)
if (settings.hasAnyChatToShowOnMap()) { if (settings.hasAnyChatToShowOnMap()) {
if (!app.osmandHelper.isOsmandBound()) { if (osmandHelper.initialized && !osmandHelper.isOsmandBound()) {
if (isChecked) { if (isChecked) {
showOsmandMissingDialog() showOsmandMissingDialog()
} }
} else { } else {
//app.shareLocationHelper.startSharingLocation() if (isChecked) {
app.showLocationHelper.showChatMessages(chatTitle)
} else {
app.showLocationHelper.hideChatMessages(chatTitle)
}
app.showLocationHelper.startShowingLocation()
} }
} else { } else {
//app.shareLocationHelper.stopSharingLocation() app.showLocationHelper.stopShowingLocation()
if (!isChecked) {
app.showLocationHelper.hideChatMessages(chatTitle)
}
} }
} }
} }

View file

@ -9,8 +9,11 @@ import android.os.Build
import android.os.Handler import android.os.Handler
import net.osmand.telegram.helpers.OsmandAidlHelper import net.osmand.telegram.helpers.OsmandAidlHelper
import net.osmand.telegram.helpers.ShareLocationHelper import net.osmand.telegram.helpers.ShareLocationHelper
import net.osmand.telegram.helpers.ShowLocationHelper
import net.osmand.telegram.helpers.TelegramHelper import net.osmand.telegram.helpers.TelegramHelper
import net.osmand.telegram.notifications.NotificationHelper import net.osmand.telegram.notifications.NotificationHelper
import net.osmand.telegram.services.MyLocationService
import net.osmand.telegram.services.UserLocationService
import net.osmand.telegram.utils.AndroidUtils import net.osmand.telegram.utils.AndroidUtils
class TelegramApplication : Application() { class TelegramApplication : Application() {
@ -18,10 +21,12 @@ class TelegramApplication : Application() {
val telegramHelper = TelegramHelper.instance val telegramHelper = TelegramHelper.instance
lateinit var settings: TelegramSettings private set lateinit var settings: TelegramSettings private set
lateinit var shareLocationHelper: ShareLocationHelper private set lateinit var shareLocationHelper: ShareLocationHelper private set
lateinit var showLocationHelper: ShowLocationHelper private set
lateinit var notificationHelper: NotificationHelper private set lateinit var notificationHelper: NotificationHelper private set
lateinit var osmandHelper: OsmandAidlHelper private set lateinit var osmandHelper: OsmandAidlHelper private set
var locationService: LocationService? = null var myLocationService: MyLocationService? = null
var userLocationService: UserLocationService? = null
private val uiHandler = Handler() private val uiHandler = Handler()
@ -33,13 +38,17 @@ class TelegramApplication : Application() {
telegramHelper.appDir = filesDir.absolutePath telegramHelper.appDir = filesDir.absolutePath
settings = TelegramSettings(this) settings = TelegramSettings(this)
shareLocationHelper = ShareLocationHelper(this)
notificationHelper = NotificationHelper(this)
osmandHelper = OsmandAidlHelper(this) osmandHelper = OsmandAidlHelper(this)
shareLocationHelper = ShareLocationHelper(this)
showLocationHelper = ShowLocationHelper(this)
notificationHelper = NotificationHelper(this)
if (settings.hasAnyChatToShareLocation() && AndroidUtils.isLocationPermissionAvailable(this)) { if (settings.hasAnyChatToShareLocation() && AndroidUtils.isLocationPermissionAvailable(this)) {
shareLocationHelper.startSharingLocation() shareLocationHelper.startSharingLocation()
} }
if (settings.hasAnyChatToShowOnMap()) {
showLocationHelper.startShowingLocation()
}
} }
override fun onTerminate() { override fun onTerminate() {
@ -80,14 +89,14 @@ class TelegramApplication : Application() {
return internetConnectionAvailable return internetConnectionAvailable
} }
fun startLocationService(restart: Boolean = false) { fun startMyLocationService(restart: Boolean = false) {
val serviceIntent = Intent(this, LocationService::class.java) val serviceIntent = Intent(this, MyLocationService::class.java)
val locationService = locationService val myLocationService = myLocationService
if (locationService != null && restart) { if (myLocationService != null && restart) {
locationService.stopSelf() myLocationService.stopSelf()
} }
if (locationService == null || restart) { if (myLocationService == null || restart) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent) startForegroundService(serviceIntent)
} else { } else {
@ -96,8 +105,28 @@ class TelegramApplication : Application() {
} }
} }
fun stopLocationService() { fun stopMyLocationService() {
locationService?.stopIfNeeded(this) myLocationService?.stopIfNeeded(this)
}
fun startUserLocationService(restart: Boolean = false) {
val serviceIntent = Intent(this, UserLocationService::class.java)
val userLocationService = userLocationService
if (userLocationService != null && restart) {
userLocationService.stopSelf()
}
if (userLocationService == null || restart) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent)
} else {
startService(serviceIntent)
}
}
}
fun stopUserLocationService() {
userLocationService?.stopIfNeeded(this)
} }
fun runInUIThread(action: (() -> Unit)) { fun runInUIThread(action: (() -> Unit)) {

View file

@ -56,6 +56,18 @@ class OsmandAidlHelper(private val app: Application) {
private var mIOsmAndAidlInterface: IOsmAndAidlInterface? = null private var mIOsmAndAidlInterface: IOsmAndAidlInterface? = null
var initialized: Boolean = false
private set
var bound: Boolean = false
private set
var listener: OsmandHelperListener? = null
interface OsmandHelperListener {
fun onOsmandConnectionStateChanged(connected: Boolean)
}
/** /**
* Class for interacting with the main interface of the service. * Class for interacting with the main interface of the service.
*/ */
@ -68,18 +80,25 @@ class OsmandAidlHelper(private val app: Application) {
// service through an IDL interface, so get a client-side // service through an IDL interface, so get a client-side
// representation of that from the raw service object. // representation of that from the raw service object.
mIOsmAndAidlInterface = IOsmAndAidlInterface.Stub.asInterface(service) mIOsmAndAidlInterface = IOsmAndAidlInterface.Stub.asInterface(service)
Toast.makeText(app, "OsmAnd service connected", Toast.LENGTH_SHORT).show() initialized = true
Toast.makeText(app, "OsmAnd connected", Toast.LENGTH_SHORT).show()
listener?.onOsmandConnectionStateChanged(true)
} }
override fun onServiceDisconnected(className: ComponentName) { override fun onServiceDisconnected(className: ComponentName) {
// This is called when the connection with the service has been // This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed. // unexpectedly disconnected -- that is, its process crashed.
mIOsmAndAidlInterface = null mIOsmAndAidlInterface = null
Toast.makeText(app, "OsmAnd service disconnected", Toast.LENGTH_SHORT).show() Toast.makeText(app, "OsmAnd disconnected", Toast.LENGTH_SHORT).show()
listener?.onOsmandConnectionStateChanged(false)
} }
} }
fun isOsmandBound(): Boolean { fun isOsmandBound(): Boolean {
return bound
}
fun isOsmandConnected(): Boolean {
return mIOsmAndAidlInterface != null return mIOsmAndAidlInterface != null
} }
@ -96,7 +115,7 @@ class OsmandAidlHelper(private val app: Application) {
if (mIOsmAndAidlInterface!!.getActiveGpx(res)) { if (mIOsmAndAidlInterface!!.getActiveGpx(res)) {
return res return res
} }
} catch (e: RemoteException) { } catch (e: Throwable) {
e.printStackTrace() e.printStackTrace()
} }
@ -106,10 +125,17 @@ class OsmandAidlHelper(private val app: Application) {
init { init {
when { when {
bindService(OSMAND_PLUS_PACKAGE_NAME) -> OSMAND_PACKAGE_NAME = OSMAND_PLUS_PACKAGE_NAME bindService(OSMAND_PLUS_PACKAGE_NAME) -> {
bindService(OSMAND_FREE_PACKAGE_NAME) -> OSMAND_PACKAGE_NAME = OSMAND_FREE_PACKAGE_NAME OSMAND_PACKAGE_NAME = OSMAND_PLUS_PACKAGE_NAME
bound = true
}
bindService(OSMAND_FREE_PACKAGE_NAME) -> {
OSMAND_PACKAGE_NAME = OSMAND_FREE_PACKAGE_NAME
bound = true
}
else -> { else -> {
Toast.makeText(app, "OsmAnd service NOT bind", Toast.LENGTH_SHORT).show() bound = false
initialized = true
} }
} }
} }
@ -118,13 +144,7 @@ class OsmandAidlHelper(private val app: Application) {
return if (mIOsmAndAidlInterface == null) { return if (mIOsmAndAidlInterface == null) {
val intent = Intent("net.osmand.aidl.OsmandAidlService") val intent = Intent("net.osmand.aidl.OsmandAidlService")
intent.`package` = packageName intent.`package` = packageName
val res = app.bindService(intent, mConnection, Context.BIND_AUTO_CREATE) app.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
if (res) {
Toast.makeText(app, "OsmAnd service bind", Toast.LENGTH_SHORT).show()
true
} else {
false
}
} else { } else {
true true
} }
@ -443,7 +463,7 @@ class OsmandAidlHelper(private val app: Application) {
* @param zOrder - z-order position of layer. Default value is 5.5f * @param zOrder - z-order position of layer. Default value is 5.5f
* @param points - initial list of points. Nullable. * @param points - initial list of points. Nullable.
*/ */
fun addMapLayer(id: String, name: String, zOrder: Float, points: List<AMapPoint>): Boolean { fun addMapLayer(id: String, name: String, zOrder: Float, points: List<AMapPoint>?): Boolean {
if (mIOsmAndAidlInterface != null) { if (mIOsmAndAidlInterface != null) {
try { try {
val layer = AMapLayer(id, name, zOrder, points) val layer = AMapLayer(id, name, zOrder, points)
@ -464,7 +484,7 @@ class OsmandAidlHelper(private val app: Application) {
* @param zOrder - z-order position of layer. Default value is 5.5f * @param zOrder - z-order position of layer. Default value is 5.5f
* @param points - list of points. Nullable. * @param points - list of points. Nullable.
*/ */
fun updateMapLayer(id: String, name: String, zOrder: Float, points: List<AMapPoint>): Boolean { fun updateMapLayer(id: String, name: String, zOrder: Float, points: List<AMapPoint>?): Boolean {
if (mIOsmAndAidlInterface != null) { if (mIOsmAndAidlInterface != null) {
try { try {
val layer = AMapLayer(id, name, zOrder, points) val layer = AMapLayer(id, name, zOrder, points)
@ -507,7 +527,7 @@ class OsmandAidlHelper(private val app: Application) {
* @param details - list of details. Displayed under context menu. * @param details - list of details. Displayed under context menu.
*/ */
fun addMapPoint(layerId: String, pointId: String, shortName: String, fullName: String, fun addMapPoint(layerId: String, pointId: String, shortName: String, fullName: String,
typeName: String, color: Int, location: ALatLon, details: List<String>): Boolean { typeName: String, color: Int, location: ALatLon, details: List<String>?): Boolean {
if (mIOsmAndAidlInterface != null) { if (mIOsmAndAidlInterface != null) {
try { try {
val point = AMapPoint(pointId, shortName, fullName, typeName, color, location, details) val point = AMapPoint(pointId, shortName, fullName, typeName, color, location, details)
@ -533,7 +553,7 @@ class OsmandAidlHelper(private val app: Application) {
* @param details - list of details. Displayed under context menu. * @param details - list of details. Displayed under context menu.
*/ */
fun updateMapPoint(layerId: String, pointId: String, shortName: String, fullName: String, fun updateMapPoint(layerId: String, pointId: String, shortName: String, fullName: String,
typeName: String, color: Int, location: ALatLon, details: List<String>): Boolean { typeName: String, color: Int, location: ALatLon, details: List<String>?): Boolean {
if (mIOsmAndAidlInterface != null) { if (mIOsmAndAidlInterface != null) {
try { try {
val point = AMapPoint(pointId, shortName, fullName, typeName, color, location, details) val point = AMapPoint(pointId, shortName, fullName, typeName, color, location, details)

View file

@ -52,29 +52,33 @@ class ShareLocationHelper(private val app: TelegramApplication) {
} }
fun startSharingLocation() { fun startSharingLocation() {
sharingLocation = true if (!sharingLocation) {
sharingLocation = true
app.startLocationService() app.startMyLocationService()
refreshNotification() refreshNotification()
}
} }
fun stopSharingLocation() { fun stopSharingLocation() {
sharingLocation = false if (sharingLocation) {
sharingLocation = false
app.stopLocationService() app.stopMyLocationService()
lastLocation = null lastLocation = null
lastTimeInMillis = 0L lastTimeInMillis = 0L
distance = 0 distance = 0
duration = 0 duration = 0
refreshNotification() refreshNotification()
}
} }
fun pauseSharingLocation() { fun pauseSharingLocation() {
sharingLocation = false sharingLocation = false
app.stopLocationService() app.stopMyLocationService()
lastLocation = null lastLocation = null
lastTimeInMillis = 0L lastTimeInMillis = 0L

View file

@ -0,0 +1,83 @@
package net.osmand.telegram.helpers
import android.graphics.Color
import net.osmand.aidl.map.ALatLon
import net.osmand.telegram.TelegramApplication
import org.drinkless.td.libcore.telegram.TdApi
class ShowLocationHelper(private val app: TelegramApplication) {
companion object {
private const val MAP_LAYER_ID = "telegram_layer"
}
private val telegramHelper = app.telegramHelper
private val osmandHelper = app.osmandHelper
var showingLocation: Boolean = false
private set
private fun setMapLayer() {
osmandHelper.addMapLayer(MAP_LAYER_ID, "Telegram", 5.5f, null)
}
fun showLocationOnMap(chatTitle: String, message: TdApi.Message) {
if (osmandHelper.isOsmandConnected()) {
val content = message.content
if (content is TdApi.MessageLocation) {
var userName = ""
val user = telegramHelper.getUser(message.senderUserId)
if (user != null) {
userName = "${user.firstName} ${user.lastName}".trim()
if (userName.isEmpty()) {
userName = user.username
}
if (userName.isEmpty()) {
userName = user.phoneNumber
}
}
if (userName.isEmpty()) {
userName = message.senderUserId.toString()
}
setMapLayer()
osmandHelper.addMapPoint(MAP_LAYER_ID, "${chatTitle}_${message.senderUserId}", userName, userName,
chatTitle, Color.RED, ALatLon(content.location.latitude, content.location.longitude), null)
}
}
}
fun showChatMessages(chatTitle: String) {
if (osmandHelper.isOsmandConnected()) {
val messages = telegramHelper.getChatMessages(chatTitle)
for (message in messages) {
showLocationOnMap(chatTitle, message)
}
}
}
fun hideChatMessages(chatTitle: String) {
if (osmandHelper.isOsmandConnected()) {
val messages = telegramHelper.getChatMessages(chatTitle)
for (message in messages) {
val user = telegramHelper.getUser(message.senderUserId)
if (user != null) {
osmandHelper.removeMapPoint(MAP_LAYER_ID, "${chatTitle}_${message.senderUserId}")
}
}
}
}
fun startShowingLocation() {
if (!showingLocation) {
showingLocation = true
app.startUserLocationService()
}
}
fun stopShowingLocation() {
if (showingLocation) {
showingLocation = false
app.stopUserLocationService()
}
}
}

View file

@ -17,6 +17,7 @@ class TelegramHelper private constructor() {
companion object { companion object {
private val log = PlatformUtil.getLog(TelegramHelper::class.java) private val log = PlatformUtil.getLog(TelegramHelper::class.java)
private const val CHATS_LIMIT = 100 private const val CHATS_LIMIT = 100
private const val CHAT_LIVE_USERS_LIMIT = 100
private const val IGNORED_ERROR_CODE = 406 private const val IGNORED_ERROR_CODE = 406
private var helper: TelegramHelper? = null private var helper: TelegramHelper? = null
@ -40,6 +41,8 @@ class TelegramHelper private constructor() {
private val chatList = TreeSet<OrderedChat>() private val chatList = TreeSet<OrderedChat>()
private val chatLiveMessages = ConcurrentHashMap<Long, Long>() private val chatLiveMessages = ConcurrentHashMap<Long, Long>()
private val usersLiveMessages = ConcurrentHashMap<Long, TdApi.Message>()
private val usersFullInfo = ConcurrentHashMap<Int, TdApi.UserFullInfo>() private val usersFullInfo = ConcurrentHashMap<Int, TdApi.UserFullInfo>()
private val basicGroupsFullInfo = ConcurrentHashMap<Int, TdApi.BasicGroupFullInfo>() private val basicGroupsFullInfo = ConcurrentHashMap<Int, TdApi.BasicGroupFullInfo>()
private val supergroupsFullInfo = ConcurrentHashMap<Int, TdApi.SupergroupFullInfo>() private val supergroupsFullInfo = ConcurrentHashMap<Int, TdApi.SupergroupFullInfo>()
@ -61,6 +64,7 @@ class TelegramHelper private constructor() {
private val liveLocationMessageUpdatesHandler = LiveLocationMessageUpdatesHandler() private val liveLocationMessageUpdatesHandler = LiveLocationMessageUpdatesHandler()
var listener: TelegramListener? = null var listener: TelegramListener? = null
var incomingMessagesListener: TelegramIncomingMessagesListener? = null
fun getChatList(): TreeSet<OrderedChat> { fun getChatList(): TreeSet<OrderedChat> {
synchronized(chatList) { synchronized(chatList) {
@ -76,6 +80,21 @@ class TelegramHelper private constructor() {
return chats[id] return chats[id]
} }
fun getUser(id: Int): TdApi.User? {
return users[id]
}
fun getChatMessages(chatTitle: String): List<TdApi.Message> {
val res = mutableListOf<TdApi.Message>()
for (message in usersLiveMessages.values) {
val title = chats[message.chatId]?.title
if (title == chatTitle) {
res.add(message)
}
}
return res
}
private fun updateChatTitles() { private fun updateChatTitles() {
chatTitles.clear() chatTitles.clear()
for (chatEntry in chats.entries) { for (chatEntry in chats.entries) {
@ -111,6 +130,10 @@ class TelegramHelper private constructor() {
fun onSendLiveLicationError(code: Int, message: String) fun onSendLiveLicationError(code: Int, message: String)
} }
interface TelegramIncomingMessagesListener {
fun onReceiveChatLocationMessages(chatTitle: String, vararg messages: TdApi.Message)
}
interface TelegramAuthorizationRequestListener { interface TelegramAuthorizationRequestListener {
fun onRequestTelegramAuthenticationParameter(parameterType: TelegramAuthenticationParameterType) fun onRequestTelegramAuthenticationParameter(parameterType: TelegramAuthenticationParameterType)
fun onTelegramAuthorizationRequestError(code: Int, message: String) fun onTelegramAuthorizationRequestError(code: Int, message: String)
@ -174,7 +197,7 @@ class TelegramHelper private constructor() {
} }
} }
fun requestChats(reload: Boolean = false) { private fun requestChats(reload: Boolean = false) {
synchronized(chatList) { synchronized(chatList) {
if (reload) { if (reload) {
chatList.clear() chatList.clear()
@ -214,9 +237,41 @@ class TelegramHelper private constructor() {
} }
} }
updateChatTitles() updateChatTitles()
getChatRecentLocationMessages(chatTitles.keys)
listener?.onTelegramChatsRead() listener?.onTelegramChatsRead()
} }
private fun getChatRecentLocationMessages(chatTitles: Set<String>) {
if (haveAuthorization) {
for (chatTitle in chatTitles) {
val chatId = this.chatTitles[chatTitle]
if (chatId != null) {
client?.send(TdApi.SearchChatRecentLocationMessages(chatId, CHAT_LIVE_USERS_LIMIT), { obj ->
when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> {
val error = obj as TdApi.Error
val code = error.code
if (code != IGNORED_ERROR_CODE && code != 400) {
listener?.onTelegramError(code, error.message)
}
}
TdApi.Messages.CONSTRUCTOR -> {
val messages = (obj as TdApi.Messages).messages
for (message in messages) {
if (!message.isOutgoing) {
usersLiveMessages[message.id] = message
}
}
incomingMessagesListener?.onReceiveChatLocationMessages(chatTitle, *messages)
}
else -> listener?.onTelegramError(-1, "Receive wrong response from TDLib: $obj")
}
})
}
}
}
}
/** /**
* @chatId Id of the chat * @chatId Id of the chat
* @livePeriod Period for which the location can be updated, in seconds; should be between 60 and 86400 for a live location and 0 otherwise. * @livePeriod Period for which the location can be updated, in seconds; should be between 60 and 86400 for a live location and 0 otherwise.
@ -338,7 +393,7 @@ class TelegramHelper private constructor() {
} }
} }
private inner class LiveLocationMessageUpdatesHandler: ResultHandler { private inner class LiveLocationMessageUpdatesHandler : ResultHandler {
override fun onResult(obj: TdApi.Object) { override fun onResult(obj: TdApi.Object) {
when (obj.constructor) { when (obj.constructor) {
TdApi.Error.CONSTRUCTOR -> { TdApi.Error.CONSTRUCTOR -> {
@ -564,6 +619,28 @@ class TelegramHelper private constructor() {
chat.unreadMentionCount = updateChat.unreadMentionCount chat.unreadMentionCount = updateChat.unreadMentionCount
} }
} }
TdApi.UpdateMessageContent.CONSTRUCTOR -> {
val updateMessageContent = obj as TdApi.UpdateMessageContent
val message = usersLiveMessages[updateMessageContent.messageId]
if (message != null && !message.isOutgoing) {
message.content = updateMessageContent.newContent
val chatTitle = chats[message.chatId]?.title
if (chatTitle != null) {
incomingMessagesListener?.onReceiveChatLocationMessages(chatTitle, message)
}
}
}
TdApi.UpdateNewMessage.CONSTRUCTOR -> {
val updateNewMessage = obj as TdApi.UpdateNewMessage
val message = updateNewMessage.message
if (!message.isOutgoing && message.content is TdApi.MessageLocation) {
usersLiveMessages[message.id] = message
val chatTitle = chats[message.chatId]?.title
if (chatTitle != null) {
incomingMessagesListener?.onReceiveChatLocationMessages(chatTitle, message)
}
}
}
TdApi.UpdateMessageMentionRead.CONSTRUCTOR -> { TdApi.UpdateMessageMentionRead.CONSTRUCTOR -> {
val updateChat = obj as TdApi.UpdateMessageMentionRead val updateChat = obj as TdApi.UpdateMessageMentionRead
val chat = chats[updateChat.chatId] val chat = chats[updateChat.chatId]

View file

@ -14,6 +14,14 @@ import net.osmand.util.Algorithms
class ShareLocationNotification(app: TelegramApplication) : TelegramNotification(app, GROUP_NAME) { class ShareLocationNotification(app: TelegramApplication) : TelegramNotification(app, GROUP_NAME) {
companion object {
const val OSMAND_START_LOCATION_SHARING_SERVICE_ACTION = "osmand_start_location_sharing_service_action"
const val OSMAND_PAUSE_LOCATION_SHARING_SERVICE_ACTION = "osmand_pause_location_sharing_service_action"
const val OSMAND_STOP_LOCATION_SHARING_SERVICE_ACTION = "osmand_stop_location_sharing_service_action"
const val GROUP_NAME = "share_location"
}
private var wasNoDataDismissed: Boolean = false private var wasNoDataDismissed: Boolean = false
private var lastBuiltNoData: Boolean = false private var lastBuiltNoData: Boolean = false
@ -25,7 +33,7 @@ class ShareLocationNotification(app: TelegramApplication) : TelegramNotification
override val isActive: Boolean override val isActive: Boolean
get() { get() {
val service = app.locationService val service = app.myLocationService
return isEnabled && service != null return isEnabled && service != null
} }
@ -141,12 +149,4 @@ class ShareLocationNotification(app: TelegramApplication) : TelegramNotification
return notificationBuilder return notificationBuilder
} }
companion object {
const val OSMAND_START_LOCATION_SHARING_SERVICE_ACTION = "osmand_start_location_sharing_service_action"
const val OSMAND_PAUSE_LOCATION_SHARING_SERVICE_ACTION = "osmand_pause_location_sharing_service_action"
const val OSMAND_STOP_LOCATION_SHARING_SERVICE_ACTION = "osmand_stop_location_sharing_service_action"
const val GROUP_NAME = "share_location"
}
} }

View file

@ -1,4 +1,4 @@
package net.osmand.telegram package net.osmand.telegram.services
import android.app.Service import android.app.Service
import android.content.Context import android.content.Context
@ -14,10 +14,13 @@ import android.util.Log
import android.widget.Toast import android.widget.Toast
import net.osmand.telegram.notifications.TelegramNotification import net.osmand.telegram.notifications.TelegramNotification
import net.osmand.PlatformUtil import net.osmand.PlatformUtil
import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
class LocationService : Service(), LocationListener { class MyLocationService : Service(), LocationListener {
private val binder = LocationServiceBinder() private val binder = LocationServiceBinder()
private fun app() = application as TelegramApplication
var handler: Handler? = null var handler: Handler? = null
@ -28,7 +31,7 @@ class LocationService : Service(), LocationListener {
} }
fun stopIfNeeded(ctx: Context) { fun stopIfNeeded(ctx: Context) {
val serviceIntent = Intent(ctx, LocationService::class.java) val serviceIntent = Intent(ctx, MyLocationService::class.java)
ctx.stopService(serviceIntent) ctx.stopService(serviceIntent)
} }
@ -36,13 +39,13 @@ class LocationService : Service(), LocationListener {
handler = Handler() handler = Handler()
val app = app() val app = app()
app.locationService = this app.myLocationService = this
// requesting // requesting
// request location updates // request location updates
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
try { try {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0f, this@LocationService) locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0f, this@MyLocationService)
} catch (e: SecurityException) { } catch (e: SecurityException) {
Toast.makeText(this, R.string.no_location_permission, Toast.LENGTH_LONG).show() Toast.makeText(this, R.string.no_location_permission, Toast.LENGTH_LONG).show()
Log.d(PlatformUtil.TAG, "Location service permission not granted") Log.d(PlatformUtil.TAG, "Location service permission not granted")
@ -51,8 +54,6 @@ class LocationService : Service(), LocationListener {
Log.d(PlatformUtil.TAG, "GPS location provider not available") Log.d(PlatformUtil.TAG, "GPS location provider not available")
} }
// registering icon at top level
// Leave icon visible even for navigation for proper display
val notification = app.notificationHelper.buildTopNotification() val notification = app.notificationHelper.buildTopNotification()
if (notification != null) { if (notification != null) {
startForeground(TelegramNotification.TOP_NOTIFICATION_SERVICE_ID, notification) startForeground(TelegramNotification.TOP_NOTIFICATION_SERVICE_ID, notification)
@ -62,12 +63,10 @@ class LocationService : Service(), LocationListener {
return Service.START_REDELIVER_INTENT return Service.START_REDELIVER_INTENT
} }
private fun app() = application as TelegramApplication
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
val app = app() val app = app()
app.locationService = null app.myLocationService = null
// remove updates // remove updates
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
@ -107,8 +106,9 @@ class LocationService : Service(), LocationListener {
override fun onTaskRemoved(rootIntent: Intent) { override fun onTaskRemoved(rootIntent: Intent) {
val app = app() val app = app()
app.notificationHelper.removeNotifications() app.notificationHelper.removeNotifications()
if (app.locationService != null) { if (app.myLocationService != null) {
this@LocationService.stopSelf() // Do not stop service after UI task was dismissed
//this@MyLocationService.stopSelf()
} }
} }

View file

@ -0,0 +1,81 @@
package net.osmand.telegram.services
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.AsyncTask
import android.os.Binder
import android.os.Handler
import android.os.IBinder
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.helpers.TelegramHelper.TelegramIncomingMessagesListener
import net.osmand.telegram.notifications.TelegramNotification
import org.drinkless.td.libcore.telegram.TdApi
import java.util.concurrent.Executors
class UserLocationService : Service(), TelegramIncomingMessagesListener {
private val binder = LocationServiceBinder()
private fun app() = application as TelegramApplication
private val executor = Executors.newSingleThreadExecutor()
var handler: Handler? = null
class LocationServiceBinder : Binder()
override fun onBind(intent: Intent): IBinder? {
return binder
}
override fun onReceiveChatLocationMessages(chatTitle: String, vararg messages: TdApi.Message) {
val app = app()
if (app.settings.isShowingChatOnMap(chatTitle)) {
ShowMessagesTask(app, chatTitle).executeOnExecutor(executor, *messages)
}
}
fun stopIfNeeded(ctx: Context) {
val serviceIntent = Intent(ctx, UserLocationService::class.java)
ctx.stopService(serviceIntent)
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
handler = Handler()
val app = app()
app.userLocationService = this
app.telegramHelper.incomingMessagesListener = this
//val notification = app.notificationHelper.buildTopNotification()
//startForeground(TelegramNotification.TOP_NOTIFICATION_SERVICE_ID, notification)
return Service.START_REDELIVER_INTENT
}
override fun onDestroy() {
super.onDestroy()
val app = app()
app.telegramHelper.incomingMessagesListener = null
app.userLocationService = null
stopForeground(java.lang.Boolean.TRUE)
}
override fun onTaskRemoved(rootIntent: Intent) {
val app = app()
if (app.userLocationService != null) {
// Do not stop service after UI task was dismissed
//this@MyLocationService.stopSelf()
}
}
class ShowMessagesTask(private val app: TelegramApplication, private val chatTitle: String) : AsyncTask<TdApi.Message, Void, Void?>() {
override fun doInBackground(vararg messages: TdApi.Message): Void? {
for (message in messages) {
app.showLocationHelper.showLocationOnMap(chatTitle, message)
}
return null
}
}
}