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) {
|
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) {
|
override fun onTelegramError(code: Int, message: String) {
|
||||||
|
|
|
@ -79,6 +79,9 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
||||||
if (isUsedByMyLocation(usedBy)) {
|
if (isUsedByMyLocation(usedBy)) {
|
||||||
initLocationUpdates()
|
initLocationUpdates()
|
||||||
}
|
}
|
||||||
|
if (isUsedByUsersLocations(usedBy)) {
|
||||||
|
app.telegramHelper.startLiveMessagesUpdates()
|
||||||
|
}
|
||||||
|
|
||||||
val locationNotification = app.notificationHelper.locationNotification
|
val locationNotification = app.notificationHelper.locationNotification
|
||||||
val notification = app.notificationHelper.buildNotification(locationNotification)
|
val notification = app.notificationHelper.buildNotification(locationNotification)
|
||||||
|
@ -100,6 +103,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
val app = app()
|
val app = app()
|
||||||
|
app.telegramHelper.stopLiveMessagesUpdates()
|
||||||
app.telegramHelper.incomingMessagesListener = null
|
app.telegramHelper.incomingMessagesListener = null
|
||||||
app.telegramService = 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?>() {
|
private class ShowMessagesTask(private val app: TelegramApplication, private val chatTitle: String) : AsyncTask<TdApi.Message, Void, Void?>() {
|
||||||
|
|
||||||
override fun doInBackground(vararg messages: TdApi.Message): Void? {
|
override fun doInBackground(vararg messages: TdApi.Message): Void? {
|
||||||
for (message in messages) {
|
for (message in messages) {
|
||||||
app.showLocationHelper.showLocationOnMap(chatTitle, message)
|
app.showLocationHelper.showLocationOnMap(message)
|
||||||
}
|
}
|
||||||
return null
|
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 {
|
companion object {
|
||||||
|
|
||||||
const val USED_BY_MY_LOCATION: Int = 1
|
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
|
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 {
|
fun isOffIntervalDepended(usedBy: Int): Boolean {
|
||||||
return isUsedByMyLocation(usedBy)
|
return isUsedByMyLocation(usedBy)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,10 @@ class TelegramSettings(private val app: TelegramApplication) {
|
||||||
private const val SPEED_CONSTANTS_KEY = "speed_constants"
|
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_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()
|
private var shareLocationChats: Set<String> = emptySet()
|
||||||
|
@ -27,6 +30,7 @@ class TelegramSettings(private val app: TelegramApplication) {
|
||||||
var speedConstants = SpeedConstants.KILOMETERS_PER_HOUR
|
var speedConstants = SpeedConstants.KILOMETERS_PER_HOUR
|
||||||
|
|
||||||
var sendMyLocationInterval = SEND_MY_LOCATION_INTERVAL_DEFAULT
|
var sendMyLocationInterval = SEND_MY_LOCATION_INTERVAL_DEFAULT
|
||||||
|
var userLocationExpireTime = USER_LOCATION_EXPIRE_TIME_DEFAULT
|
||||||
|
|
||||||
init {
|
init {
|
||||||
read()
|
read()
|
||||||
|
@ -130,5 +134,6 @@ class TelegramSettings(private val app: TelegramApplication) {
|
||||||
speedConstants = SpeedConstants.valueOf(prefs.getString(SPEED_CONSTANTS_KEY, SpeedConstants.KILOMETERS_PER_HOUR.name))
|
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)
|
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 {
|
companion object {
|
||||||
private const val OSMAND_FREE_PACKAGE_NAME = "net.osmand"
|
private const val OSMAND_FREE_PACKAGE_NAME = "net.osmand"
|
||||||
private const val OSMAND_PLUS_PACKAGE_NAME = "net.osmand.plus"
|
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
|
private var mIOsmAndAidlInterface: IOsmAndAidlInterface? = null
|
||||||
|
|
|
@ -24,13 +24,30 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
||||||
private set
|
private set
|
||||||
|
|
||||||
fun setupMapLayer() {
|
fun setupMapLayer() {
|
||||||
|
execOsmandApi {
|
||||||
osmandHelper.addMapLayer(MAP_LAYER_ID, "Telegram", 5.5f, null)
|
osmandHelper.addMapLayer(MAP_LAYER_ID, "Telegram", 5.5f, null)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun showLocationOnMap(chatTitle: String, message: TdApi.Message) {
|
fun updateLocationsOnMap() {
|
||||||
if (osmandHelper.isOsmandConnected()) {
|
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
|
val content = message.content
|
||||||
if (content is TdApi.MessageLocation) {
|
if (chatTitle != null && content is TdApi.MessageLocation) {
|
||||||
var userName = ""
|
var userName = ""
|
||||||
var photoUri: Uri? = null
|
var photoUri: Uri? = null
|
||||||
val user = telegramHelper.getUser(message.senderUserId)
|
val user = telegramHelper.getUser(message.senderUserId)
|
||||||
|
@ -45,7 +62,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
||||||
val photoPath = telegramHelper.getUserPhotoPath(user)
|
val photoPath = telegramHelper.getUserPhotoPath(user)
|
||||||
if (!TextUtils.isEmpty(photoPath)) {
|
if (!TextUtils.isEmpty(photoPath)) {
|
||||||
photoUri = AndroidUtils.getUriForFile(app, File(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()) {
|
if (userName.isEmpty()) {
|
||||||
|
@ -59,22 +76,20 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
||||||
osmandHelper.addMapPoint(MAP_LAYER_ID, "${chatTitle}_${message.senderUserId}", userName, userName,
|
osmandHelper.addMapPoint(MAP_LAYER_ID, "${chatTitle}_${message.senderUserId}", userName, userName,
|
||||||
chatTitle, Color.RED, ALatLon(content.location.latitude, content.location.longitude), null, params)
|
chatTitle, Color.RED, ALatLon(content.location.latitude, content.location.longitude), null, params)
|
||||||
}
|
}
|
||||||
} else if (osmandHelper.isOsmandBound()) {
|
|
||||||
osmandHelper.connectOsmand()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showChatMessages(chatTitle: String) {
|
fun showChatMessages(chatTitle: String) {
|
||||||
if (osmandHelper.isOsmandConnected()) {
|
execOsmandApi {
|
||||||
val messages = telegramHelper.getChatMessages(chatTitle)
|
val messages = telegramHelper.getChatMessages(chatTitle)
|
||||||
for (message in messages) {
|
for (message in messages) {
|
||||||
showLocationOnMap(chatTitle, message)
|
showLocationOnMap(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hideChatMessages(chatTitle: String) {
|
fun hideChatMessages(chatTitle: String) {
|
||||||
if (osmandHelper.isOsmandConnected()) {
|
execOsmandApi {
|
||||||
val messages = telegramHelper.getChatMessages(chatTitle)
|
val messages = telegramHelper.getChatMessages(chatTitle)
|
||||||
for (message in messages) {
|
for (message in messages) {
|
||||||
val user = telegramHelper.getUser(message.senderUserId)
|
val user = telegramHelper.getUser(message.senderUserId)
|
||||||
|
@ -98,4 +113,12 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
||||||
app.stopUserLocationService()
|
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.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.ScheduledExecutorService
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
|
||||||
class TelegramHelper private constructor() {
|
class TelegramHelper private constructor() {
|
||||||
|
@ -19,6 +22,7 @@ class TelegramHelper private constructor() {
|
||||||
private const val CHATS_LIMIT = 100
|
private const val CHATS_LIMIT = 100
|
||||||
private const val CHAT_LIVE_USERS_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 const val UPDATE_LIVE_MESSAGES_INTERVAL_SEC = 30L
|
||||||
|
|
||||||
private var helper: TelegramHelper? = null
|
private var helper: TelegramHelper? = null
|
||||||
|
|
||||||
|
@ -66,6 +70,8 @@ class TelegramHelper private constructor() {
|
||||||
private val defaultHandler = DefaultHandler()
|
private val defaultHandler = DefaultHandler()
|
||||||
private val liveLocationMessageUpdatesHandler = LiveLocationMessageUpdatesHandler()
|
private val liveLocationMessageUpdatesHandler = LiveLocationMessageUpdatesHandler()
|
||||||
|
|
||||||
|
private var updateLiveMessagesExecutor: ScheduledExecutorService? = null
|
||||||
|
|
||||||
var listener: TelegramListener? = null
|
var listener: TelegramListener? = null
|
||||||
var incomingMessagesListener: TelegramIncomingMessagesListener? = null
|
var incomingMessagesListener: TelegramIncomingMessagesListener? = null
|
||||||
|
|
||||||
|
@ -98,6 +104,15 @@ class TelegramHelper private constructor() {
|
||||||
return users[id]
|
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> {
|
fun getChatMessages(chatTitle: String): List<TdApi.Message> {
|
||||||
val res = mutableListOf<TdApi.Message>()
|
val res = mutableListOf<TdApi.Message>()
|
||||||
for (message in usersLiveMessages.values) {
|
for (message in usersLiveMessages.values) {
|
||||||
|
@ -109,6 +124,10 @@ class TelegramHelper private constructor() {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getMessages(): List<TdApi.Message> {
|
||||||
|
return usersLiveMessages.values.toList()
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateChatTitles() {
|
private fun updateChatTitles() {
|
||||||
chatTitles.clear()
|
chatTitles.clear()
|
||||||
for (chatEntry in chats.entries) {
|
for (chatEntry in chats.entries) {
|
||||||
|
@ -148,6 +167,7 @@ class TelegramHelper private constructor() {
|
||||||
|
|
||||||
interface TelegramIncomingMessagesListener {
|
interface TelegramIncomingMessagesListener {
|
||||||
fun onReceiveChatLocationMessages(chatTitle: String, vararg messages: TdApi.Message)
|
fun onReceiveChatLocationMessages(chatTitle: String, vararg messages: TdApi.Message)
|
||||||
|
fun updateLocationMessages()
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TelegramAuthorizationRequestListener {
|
interface TelegramAuthorizationRequestListener {
|
||||||
|
@ -217,7 +237,7 @@ class TelegramHelper private constructor() {
|
||||||
return client != null && haveAuthorization
|
return client != null && haveAuthorization
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUserPhotoPath(user: TdApi.User):String? {
|
fun getUserPhotoPath(user: TdApi.User): String? {
|
||||||
return if (hasLocalUserPhoto(user)) {
|
return if (hasLocalUserPhoto(user)) {
|
||||||
user.profilePhoto?.small?.local?.path
|
user.profilePhoto?.small?.local?.path
|
||||||
} else {
|
} 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 {
|
private fun hasLocalUserPhoto(user: TdApi.User): Boolean {
|
||||||
val localPhoto = user.profilePhoto?.small?.local
|
val localPhoto = user.profilePhoto?.small?.local
|
||||||
return if (localPhoto != null) {
|
return if (localPhoto != null) {
|
||||||
|
@ -326,7 +361,7 @@ class TelegramHelper private constructor() {
|
||||||
TdApi.Messages.CONSTRUCTOR -> {
|
TdApi.Messages.CONSTRUCTOR -> {
|
||||||
val messages = (obj as TdApi.Messages).messages
|
val messages = (obj as TdApi.Messages).messages
|
||||||
for (message in messages) {
|
for (message in messages) {
|
||||||
if (!message.isOutgoing) {
|
if (!message.isOutgoing && message.content is TdApi.MessageLocation) {
|
||||||
usersLiveMessages[message.id] = message
|
usersLiveMessages[message.id] = message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,6 +95,11 @@ public class AidlMapLayer extends OsmandMapLayer implements IContextMenuProvider
|
||||||
return (int) (r * tb.getDensity());
|
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
|
@Override
|
||||||
public void onDraw(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
|
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 ex = (int) point.x;
|
||||||
int ey = (int) point.y;
|
int ey = (int) point.y;
|
||||||
final int rp = getRadiusPoi(tb);
|
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;
|
int radius = rp * 3 / 2;
|
||||||
for (AMapPoint p : aidlLayer.getPoints()) {
|
for (AMapPoint p : aidlLayer.getPoints()) {
|
||||||
ALatLon position = p.getLocation();
|
ALatLon position = p.getLocation();
|
||||||
if (position != null) {
|
if (position != null) {
|
||||||
|
compare = hasBitmap(p) ? bitmapRadius : radius;
|
||||||
int x = (int) tb.getPixXFromLatLon(position.getLatitude(), position.getLongitude());
|
int x = (int) tb.getPixXFromLatLon(position.getLatitude(), position.getLongitude());
|
||||||
int y = (int) tb.getPixYFromLatLon(position.getLatitude(), position.getLongitude());
|
int y = (int) tb.getPixYFromLatLon(position.getLatitude(), position.getLongitude());
|
||||||
if (Math.abs(x - ex) <= compare && Math.abs(y - ey) <= compare) {
|
if (Math.abs(x - ex) <= compare && Math.abs(y - ey) <= compare) {
|
||||||
compare = radius;
|
|
||||||
points.add(p);
|
points.add(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue