Telegram - added location expire feature
This commit is contained in:
parent
35b2ce93fe
commit
c3ca853451
7 changed files with 111 additions and 18 deletions
|
@ -173,7 +173,10 @@ class MainActivity : AppCompatActivity(), TelegramListener {
|
|||
}
|
||||
|
||||
override fun onTelegramUserChanged(user: TdApi.User) {
|
||||
|
||||
val message = telegramHelper.getUserMessage(user)
|
||||
if (message != null) {
|
||||
app.showLocationHelper.showLocationOnMap(message)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTelegramError(code: Int, message: String) {
|
||||
|
|
|
@ -79,6 +79,9 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
if (isUsedByMyLocation(usedBy)) {
|
||||
initLocationUpdates()
|
||||
}
|
||||
if (isUsedByUsersLocations(usedBy)) {
|
||||
app.telegramHelper.startLiveMessagesUpdates()
|
||||
}
|
||||
|
||||
val locationNotification = app.notificationHelper.locationNotification
|
||||
val notification = app.notificationHelper.buildNotification(locationNotification)
|
||||
|
@ -100,6 +103,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
val app = app()
|
||||
app.telegramHelper.stopLiveMessagesUpdates()
|
||||
app.telegramHelper.incomingMessagesListener = null
|
||||
app.telegramService = null
|
||||
|
||||
|
@ -204,16 +208,28 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
}
|
||||
}
|
||||
|
||||
override fun updateLocationMessages() {
|
||||
UpdateMessagesTask(app()).executeOnExecutor(executor)
|
||||
}
|
||||
|
||||
private 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)
|
||||
app.showLocationHelper.showLocationOnMap(message)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private class UpdateMessagesTask(private val app: TelegramApplication) : AsyncTask<Void, Void, Void?>() {
|
||||
|
||||
override fun doInBackground(vararg params: Void?): Void? {
|
||||
app.showLocationHelper.updateLocationsOnMap()
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val USED_BY_MY_LOCATION: Int = 1
|
||||
|
@ -242,6 +258,10 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
return (usedBy and USED_BY_MY_LOCATION) > 0
|
||||
}
|
||||
|
||||
fun isUsedByUsersLocations(usedBy: Int): Boolean {
|
||||
return (usedBy and USED_BY_USERS_LOCATIONS) > 0
|
||||
}
|
||||
|
||||
fun isOffIntervalDepended(usedBy: Int): Boolean {
|
||||
return isUsedByMyLocation(usedBy)
|
||||
}
|
||||
|
|
|
@ -17,7 +17,10 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
private const val SPEED_CONSTANTS_KEY = "speed_constants"
|
||||
|
||||
private const val SEND_MY_LOCATION_INTERVAL_KEY = "send_my_location_interval"
|
||||
private const val SEND_MY_LOCATION_INTERVAL_DEFAULT = 5000L
|
||||
private const val SEND_MY_LOCATION_INTERVAL_DEFAULT = 5L * 1000 // 5 seconds
|
||||
|
||||
private const val USER_LOCATION_EXPIRE_TIME_KEY = "user_location_expire_time"
|
||||
private const val USER_LOCATION_EXPIRE_TIME_DEFAULT = 15L * 60 * 1000 // 15 minutes
|
||||
}
|
||||
|
||||
private var shareLocationChats: Set<String> = emptySet()
|
||||
|
@ -27,6 +30,7 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
var speedConstants = SpeedConstants.KILOMETERS_PER_HOUR
|
||||
|
||||
var sendMyLocationInterval = SEND_MY_LOCATION_INTERVAL_DEFAULT
|
||||
var userLocationExpireTime = USER_LOCATION_EXPIRE_TIME_DEFAULT
|
||||
|
||||
init {
|
||||
read()
|
||||
|
@ -130,5 +134,6 @@ class TelegramSettings(private val app: TelegramApplication) {
|
|||
speedConstants = SpeedConstants.valueOf(prefs.getString(SPEED_CONSTANTS_KEY, SpeedConstants.KILOMETERS_PER_HOUR.name))
|
||||
|
||||
sendMyLocationInterval = prefs.getLong(SEND_MY_LOCATION_INTERVAL_KEY, SEND_MY_LOCATION_INTERVAL_DEFAULT)
|
||||
userLocationExpireTime = prefs.getLong(USER_LOCATION_EXPIRE_TIME_KEY, USER_LOCATION_EXPIRE_TIME_DEFAULT)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,8 @@ class OsmandAidlHelper(private val app: Application) {
|
|||
companion object {
|
||||
private const val OSMAND_FREE_PACKAGE_NAME = "net.osmand"
|
||||
private const val OSMAND_PLUS_PACKAGE_NAME = "net.osmand.plus"
|
||||
private var OSMAND_PACKAGE_NAME = OSMAND_PLUS_PACKAGE_NAME
|
||||
var OSMAND_PACKAGE_NAME = OSMAND_PLUS_PACKAGE_NAME
|
||||
private set
|
||||
}
|
||||
|
||||
private var mIOsmAndAidlInterface: IOsmAndAidlInterface? = null
|
||||
|
|
|
@ -24,13 +24,30 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
|||
private set
|
||||
|
||||
fun setupMapLayer() {
|
||||
osmandHelper.addMapLayer(MAP_LAYER_ID, "Telegram", 5.5f, null)
|
||||
execOsmandApi {
|
||||
osmandHelper.addMapLayer(MAP_LAYER_ID, "Telegram", 5.5f, null)
|
||||
}
|
||||
}
|
||||
|
||||
fun showLocationOnMap(chatTitle: String, message: TdApi.Message) {
|
||||
if (osmandHelper.isOsmandConnected()) {
|
||||
fun updateLocationsOnMap() {
|
||||
execOsmandApi {
|
||||
val messages = telegramHelper.getMessages()
|
||||
for (message in messages) {
|
||||
val chatTitle = telegramHelper.getChat(message.chatId)?.title
|
||||
val date = Math.max(message.date, message.editDate) * 1000L
|
||||
val expired = System.currentTimeMillis() - date > app.settings.userLocationExpireTime
|
||||
if (chatTitle != null && message.content is TdApi.MessageLocation && expired) {
|
||||
osmandHelper.removeMapPoint(MAP_LAYER_ID, "${chatTitle}_${message.senderUserId}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun showLocationOnMap(message: TdApi.Message) {
|
||||
execOsmandApi {
|
||||
val chatTitle = telegramHelper.getChat(message.chatId)?.title
|
||||
val content = message.content
|
||||
if (content is TdApi.MessageLocation) {
|
||||
if (chatTitle != null && content is TdApi.MessageLocation) {
|
||||
var userName = ""
|
||||
var photoUri: Uri? = null
|
||||
val user = telegramHelper.getUser(message.senderUserId)
|
||||
|
@ -45,7 +62,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
|||
val photoPath = telegramHelper.getUserPhotoPath(user)
|
||||
if (!TextUtils.isEmpty(photoPath)) {
|
||||
photoUri = AndroidUtils.getUriForFile(app, File(photoPath))
|
||||
app.grantUriPermission("net.osmand.plus", photoUri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
app.grantUriPermission(OsmandAidlHelper.OSMAND_PACKAGE_NAME, photoUri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
}
|
||||
if (userName.isEmpty()) {
|
||||
|
@ -59,22 +76,20 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
|||
osmandHelper.addMapPoint(MAP_LAYER_ID, "${chatTitle}_${message.senderUserId}", userName, userName,
|
||||
chatTitle, Color.RED, ALatLon(content.location.latitude, content.location.longitude), null, params)
|
||||
}
|
||||
} else if (osmandHelper.isOsmandBound()) {
|
||||
osmandHelper.connectOsmand()
|
||||
}
|
||||
}
|
||||
|
||||
fun showChatMessages(chatTitle: String) {
|
||||
if (osmandHelper.isOsmandConnected()) {
|
||||
execOsmandApi {
|
||||
val messages = telegramHelper.getChatMessages(chatTitle)
|
||||
for (message in messages) {
|
||||
showLocationOnMap(chatTitle, message)
|
||||
showLocationOnMap(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun hideChatMessages(chatTitle: String) {
|
||||
if (osmandHelper.isOsmandConnected()) {
|
||||
execOsmandApi {
|
||||
val messages = telegramHelper.getChatMessages(chatTitle)
|
||||
for (message in messages) {
|
||||
val user = telegramHelper.getUser(message.senderUserId)
|
||||
|
@ -98,4 +113,12 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
|||
app.stopUserLocationService()
|
||||
}
|
||||
}
|
||||
|
||||
private fun execOsmandApi(action: (() -> Unit)) {
|
||||
if (osmandHelper.isOsmandConnected()) {
|
||||
action.invoke()
|
||||
} else if (osmandHelper.isOsmandBound()) {
|
||||
osmandHelper.connectOsmand()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,9 @@ import org.drinkless.td.libcore.telegram.TdApi.AuthorizationState
|
|||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.ScheduledExecutorService
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
class TelegramHelper private constructor() {
|
||||
|
@ -19,6 +22,7 @@ class TelegramHelper private constructor() {
|
|||
private const val CHATS_LIMIT = 100
|
||||
private const val CHAT_LIVE_USERS_LIMIT = 100
|
||||
private const val IGNORED_ERROR_CODE = 406
|
||||
private const val UPDATE_LIVE_MESSAGES_INTERVAL_SEC = 30L
|
||||
|
||||
private var helper: TelegramHelper? = null
|
||||
|
||||
|
@ -66,6 +70,8 @@ class TelegramHelper private constructor() {
|
|||
private val defaultHandler = DefaultHandler()
|
||||
private val liveLocationMessageUpdatesHandler = LiveLocationMessageUpdatesHandler()
|
||||
|
||||
private var updateLiveMessagesExecutor: ScheduledExecutorService? = null
|
||||
|
||||
var listener: TelegramListener? = null
|
||||
var incomingMessagesListener: TelegramIncomingMessagesListener? = null
|
||||
|
||||
|
@ -98,6 +104,15 @@ class TelegramHelper private constructor() {
|
|||
return users[id]
|
||||
}
|
||||
|
||||
fun getUserMessage(user: TdApi.User): TdApi.Message? {
|
||||
for (message in usersLiveMessages.values) {
|
||||
if (message.senderUserId == user.id) {
|
||||
return message
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun getChatMessages(chatTitle: String): List<TdApi.Message> {
|
||||
val res = mutableListOf<TdApi.Message>()
|
||||
for (message in usersLiveMessages.values) {
|
||||
|
@ -109,6 +124,10 @@ class TelegramHelper private constructor() {
|
|||
return res
|
||||
}
|
||||
|
||||
fun getMessages(): List<TdApi.Message> {
|
||||
return usersLiveMessages.values.toList()
|
||||
}
|
||||
|
||||
private fun updateChatTitles() {
|
||||
chatTitles.clear()
|
||||
for (chatEntry in chats.entries) {
|
||||
|
@ -148,6 +167,7 @@ class TelegramHelper private constructor() {
|
|||
|
||||
interface TelegramIncomingMessagesListener {
|
||||
fun onReceiveChatLocationMessages(chatTitle: String, vararg messages: TdApi.Message)
|
||||
fun updateLocationMessages()
|
||||
}
|
||||
|
||||
interface TelegramAuthorizationRequestListener {
|
||||
|
@ -217,7 +237,7 @@ class TelegramHelper private constructor() {
|
|||
return client != null && haveAuthorization
|
||||
}
|
||||
|
||||
fun getUserPhotoPath(user: TdApi.User):String? {
|
||||
fun getUserPhotoPath(user: TdApi.User): String? {
|
||||
return if (hasLocalUserPhoto(user)) {
|
||||
user.profilePhoto?.small?.local?.path
|
||||
} else {
|
||||
|
@ -228,6 +248,21 @@ class TelegramHelper private constructor() {
|
|||
}
|
||||
}
|
||||
|
||||
fun startLiveMessagesUpdates() {
|
||||
stopLiveMessagesUpdates()
|
||||
|
||||
val updateLiveMessagesExecutor = Executors.newSingleThreadScheduledExecutor()
|
||||
this.updateLiveMessagesExecutor = updateLiveMessagesExecutor
|
||||
updateLiveMessagesExecutor.scheduleWithFixedDelay({
|
||||
incomingMessagesListener?.updateLocationMessages()
|
||||
}, UPDATE_LIVE_MESSAGES_INTERVAL_SEC, UPDATE_LIVE_MESSAGES_INTERVAL_SEC, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
fun stopLiveMessagesUpdates() {
|
||||
updateLiveMessagesExecutor?.shutdown()
|
||||
updateLiveMessagesExecutor?.awaitTermination(1, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
private fun hasLocalUserPhoto(user: TdApi.User): Boolean {
|
||||
val localPhoto = user.profilePhoto?.small?.local
|
||||
return if (localPhoto != null) {
|
||||
|
@ -326,7 +361,7 @@ class TelegramHelper private constructor() {
|
|||
TdApi.Messages.CONSTRUCTOR -> {
|
||||
val messages = (obj as TdApi.Messages).messages
|
||||
for (message in messages) {
|
||||
if (!message.isOutgoing) {
|
||||
if (!message.isOutgoing && message.content is TdApi.MessageLocation) {
|
||||
usersLiveMessages[message.id] = message
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,11 @@ public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider
|
|||
return (int) (r * tb.getDensity());
|
||||
}
|
||||
|
||||
private boolean hasBitmap(AMapPoint point) {
|
||||
String imageUriStr = point.getParams().get(AMapPoint.POINT_IMAGE_URI_PARAM);
|
||||
return !TextUtils.isEmpty(imageUriStr) && pointImages.containsKey(imageUriStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
|
||||
}
|
||||
|
@ -208,15 +213,16 @@ public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider
|
|||
int ex = (int) point.x;
|
||||
int ey = (int) point.y;
|
||||
final int rp = getRadiusPoi(tb);
|
||||
int compare = rp;
|
||||
final int bitmapRadius = (int) (POINT_IMAGE_SIZE_PX / tb.getDensity());
|
||||
int compare;
|
||||
int radius = rp * 3 / 2;
|
||||
for (AMapPoint p : aidlLayer.getPoints()) {
|
||||
ALatLon position = p.getLocation();
|
||||
if (position != null) {
|
||||
compare = hasBitmap(p) ? bitmapRadius : radius;
|
||||
int x = (int) tb.getPixXFromLatLon(position.getLatitude(), position.getLongitude());
|
||||
int y = (int) tb.getPixYFromLatLon(position.getLatitude(), position.getLongitude());
|
||||
if (Math.abs(x - ex) <= compare && Math.abs(y - ey) <= compare) {
|
||||
compare = radius;
|
||||
points.add(p);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue