Telegram - added location expire feature

This commit is contained in:
crimean 2018-06-16 14:55:14 +03:00
parent 35b2ce93fe
commit c3ca853451
7 changed files with 111 additions and 18 deletions

View file

@ -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) {

View file

@ -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)
}

View file

@ -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)
}
}

View file

@ -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

View file

@ -24,13 +24,30 @@ class ShowLocationHelper(private val app: TelegramApplication) {
private set
fun setupMapLayer() {
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()
}
}
}

View file

@ -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
}
}

View file

@ -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);
}
}