Merge pull request #8185 from osmandapp/Widget_for_Tracker_in_OsmAnd
Widget for tracker in osm and
This commit is contained in:
commit
a6300d5c3d
10 changed files with 157 additions and 0 deletions
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="status_widget_title">OsmAnd Tracker status</string>
|
||||
<string name="buffer_time_descr">Maximum time to store points in the buffer</string>
|
||||
<string name="buffer_time">Buffer expiration time</string>
|
||||
<string name="time_zone_descr">Select time zone to show in your location messages.</string>
|
||||
|
|
|
@ -56,6 +56,7 @@ class TelegramApplication : Application(), OsmandHelperListener {
|
|||
)
|
||||
showLocationHelper.addDirectionContextMenuButton()
|
||||
showLocationHelper.startShowingLocation()
|
||||
showLocationHelper.addOrUpdateStatusWidget(-1, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,12 +20,15 @@ import net.osmand.telegram.utils.AndroidUtils
|
|||
import org.drinkless.td.libcore.telegram.TdApi
|
||||
import java.util.*
|
||||
|
||||
private const val UPDATE_WIDGET_INTERVAL_MS = 1000L // 1 sec
|
||||
private const val UPDATE_LIVE_MESSAGES_INTERVAL_MS = 10000L // 10 sec
|
||||
private const val UPDATE_LIVE_TRACKS_INTERVAL_MS = 30000L // 30 sec
|
||||
|
||||
class TelegramService : Service(), LocationListener, TelegramIncomingMessagesListener,
|
||||
TelegramOutgoingMessagesListener {
|
||||
|
||||
private val log = PlatformUtil.getLog(TelegramService::class.java)
|
||||
|
||||
private fun app() = application as TelegramApplication
|
||||
private val binder = LocationServiceBinder()
|
||||
private var shouldCleanupResources: Boolean = false
|
||||
|
@ -36,6 +39,9 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
private var updateTracksHandler: Handler? = null
|
||||
private var tracksHandlerThread = HandlerThread("TracksUpdateServiceThread")
|
||||
|
||||
private var updateWidgetHandler: Handler? = null
|
||||
private var updateWidgetThread = HandlerThread("WidgetUpdateServiceThread")
|
||||
|
||||
var handler: Handler? = null
|
||||
private set
|
||||
var usedBy = 0
|
||||
|
@ -58,8 +64,10 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
super.onCreate()
|
||||
mHandlerThread.start()
|
||||
tracksHandlerThread.start()
|
||||
updateWidgetThread.start()
|
||||
updateShareInfoHandler = Handler(mHandlerThread.looper)
|
||||
updateTracksHandler = Handler(tracksHandlerThread.looper)
|
||||
updateWidgetHandler = Handler(updateWidgetThread.looper)
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? {
|
||||
|
@ -106,6 +114,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
if (isUsedByMyLocation(usedBy)) {
|
||||
initLocationUpdates()
|
||||
startShareInfoUpdates()
|
||||
startWidgetUpdates()
|
||||
}
|
||||
if (isUsedByUsersLocations(usedBy)) {
|
||||
app.telegramHelper.startLiveMessagesUpdates(app.settings.sendMyLocInterval)
|
||||
|
@ -139,6 +148,8 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
app.telegramService = null
|
||||
tracksHandlerThread.quit()
|
||||
mHandlerThread.quit()
|
||||
updateWidgetThread.quit()
|
||||
app().showLocationHelper.addOrUpdateStatusWidget(-1, false)
|
||||
|
||||
usedBy = 0
|
||||
|
||||
|
@ -209,6 +220,33 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
|
|||
}
|
||||
}, UPDATE_LIVE_TRACKS_INTERVAL_MS)
|
||||
}
|
||||
|
||||
private fun startWidgetUpdates() {
|
||||
updateWidgetHandler?.postDelayed({
|
||||
if (isUsedByMyLocation(usedBy)) {
|
||||
val sharingStatus = app().settings.sharingStatusChanges.last()
|
||||
val isSending = sharingStatus.statusType == TelegramSettings.SharingStatusType.SENDING
|
||||
val sharingChats = app().settings.getShareLocationChats()
|
||||
var oldestTime = 0L
|
||||
if (sharingChats.isNotEmpty()) {
|
||||
sharingChats.forEach { id ->
|
||||
val bufferMessages = app().locationMessages.getBufferedMessagesForChat(id)
|
||||
if (bufferMessages.isNotEmpty()) {
|
||||
val newTime = bufferMessages[0].time
|
||||
if (oldestTime == 0L || newTime < oldestTime) {
|
||||
oldestTime = newTime
|
||||
}
|
||||
} else {
|
||||
oldestTime = 0L
|
||||
}
|
||||
}
|
||||
}
|
||||
log.info("oldest buffered msg time: $oldestTime | isSending: $isSending")
|
||||
app().showLocationHelper.addOrUpdateStatusWidget(oldestTime, isSending)
|
||||
}
|
||||
startWidgetUpdates()
|
||||
}, UPDATE_WIDGET_INTERVAL_MS)
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
private fun getFirstTimeRunDefaultLocation(): net.osmand.Location? {
|
||||
|
|
|
@ -43,6 +43,15 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
|||
|
||||
const val GPX_COLORS_COUNT = 10
|
||||
|
||||
private const val STATUS_WIDGET_ID = "status_widget"
|
||||
private const val STATUS_WIDGET_MENU_ICON = "widget_location_sharing_night"
|
||||
private const val STATUS_WIDGET_ANIM_ICON_DAY = "anim_widget_location_sharing_day"
|
||||
private const val STATUS_WIDGET_ANIM_ICON_NIGHT = "anim_widget_location_sharing_night"
|
||||
private const val STATUS_WIDGET_ON_ANIM_ICON_DAY = "anim_widget_location_sharing_on_day"
|
||||
private const val STATUS_WIDGET_ON_ANIM_ICON_NIGHT = "anim_widget_location_sharing_on_night"
|
||||
private const val STATUS_WIDGET_OFF_ICON_DAY = "widget_location_sharing_off_day"
|
||||
private const val STATUS_WIDGET_OFF_ICON_NIGHT = "widget_location_sharing_off_night"
|
||||
|
||||
val GPX_COLORS = arrayOf(
|
||||
"red", "orange", "lightblue", "blue", "purple",
|
||||
"translucent_red", "translucent_orange", "translucent_lightblue",
|
||||
|
@ -198,6 +207,57 @@ class ShowLocationHelper(private val app: TelegramApplication) {
|
|||
}
|
||||
}
|
||||
|
||||
fun addOrUpdateStatusWidget(time: Long, isSending: Boolean) {
|
||||
val iconDay: String
|
||||
val iconNight: String
|
||||
val text = when {
|
||||
time > 0L -> {
|
||||
iconDay = STATUS_WIDGET_ANIM_ICON_DAY
|
||||
iconNight = STATUS_WIDGET_ANIM_ICON_NIGHT
|
||||
val diffTime = (System.currentTimeMillis() - time) / 1000
|
||||
OsmandFormatter.getFormattedDurationForWidget(diffTime)
|
||||
}
|
||||
time == 0L && isSending -> {
|
||||
iconDay = STATUS_WIDGET_ON_ANIM_ICON_DAY
|
||||
iconNight = STATUS_WIDGET_ON_ANIM_ICON_NIGHT
|
||||
app.getString(R.string.shared_string_ok)
|
||||
}
|
||||
time == 0L && !isSending -> {
|
||||
iconDay = STATUS_WIDGET_ANIM_ICON_DAY
|
||||
iconNight = STATUS_WIDGET_ANIM_ICON_NIGHT
|
||||
app.getString(R.string.shared_string_ok)
|
||||
}
|
||||
else -> {
|
||||
iconDay = STATUS_WIDGET_OFF_ICON_DAY
|
||||
iconNight = STATUS_WIDGET_OFF_ICON_NIGHT
|
||||
app.getString(R.string.shared_string_start)
|
||||
}
|
||||
}
|
||||
val subText = when {
|
||||
time > 0 -> {
|
||||
if (text.length > 2) {
|
||||
app.getString(R.string.shared_string_hour_short)
|
||||
} else {
|
||||
app.getString(R.string.shared_string_minute_short)
|
||||
}
|
||||
}
|
||||
else -> ""
|
||||
}
|
||||
osmandAidlHelper.addMapWidget(
|
||||
STATUS_WIDGET_ID,
|
||||
STATUS_WIDGET_MENU_ICON,
|
||||
app.getString(R.string.status_widget_title),
|
||||
iconDay,
|
||||
iconNight,
|
||||
text, subText, 50, getStatusWidgetIntent())
|
||||
}
|
||||
|
||||
private fun getStatusWidgetIntent(): Intent {
|
||||
val startIntent = app.packageManager.getLaunchIntentForPackage(app.packageName)
|
||||
startIntent.addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
return startIntent
|
||||
}
|
||||
|
||||
private fun getALatLonFromMessage(content: TdApi.MessageContent): ALatLon? {
|
||||
return when (content) {
|
||||
is TdApi.MessageLocation -> ALatLon(content.location.latitude, content.location.longitude)
|
||||
|
|
|
@ -45,6 +45,18 @@ object OsmandFormatter {
|
|||
fixed2.minimumIntegerDigits = 1
|
||||
}
|
||||
|
||||
fun getFormattedDurationForWidget(seconds: Long): String {
|
||||
val hours = seconds / (60 * 60)
|
||||
val minutes = seconds / 60 % 60
|
||||
return when {
|
||||
hours > 9 -> String.format("%10d:%01d", hours, minutes)
|
||||
hours > 0 -> String.format("%1d:%01d", hours, minutes)
|
||||
minutes > 9 -> String.format("%11d", minutes)
|
||||
minutes > 0 -> String.format("%1d", minutes)
|
||||
else -> "1"
|
||||
}.trim()
|
||||
}
|
||||
|
||||
fun getFormattedDuration(ctx: Context, seconds: Long, short: Boolean = false): String {
|
||||
val hours = seconds / (60 * 60)
|
||||
val minutes = seconds / 60 % 60
|
||||
|
|
10
OsmAnd/res/drawable/anim_widget_location_sharing_day.xml
Normal file
10
OsmAnd/res/drawable/anim_widget_location_sharing_day.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:oneshot="false">
|
||||
<item
|
||||
android:drawable="@drawable/widget_location_sharing_day"
|
||||
android:duration="500" />
|
||||
<item
|
||||
android:drawable="@drawable/widget_location_sharing_off_day"
|
||||
android:duration="500" />
|
||||
</animation-list>
|
10
OsmAnd/res/drawable/anim_widget_location_sharing_night.xml
Normal file
10
OsmAnd/res/drawable/anim_widget_location_sharing_night.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:oneshot="false">
|
||||
<item
|
||||
android:drawable="@drawable/widget_location_sharing_night"
|
||||
android:duration="500" />
|
||||
<item
|
||||
android:drawable="@drawable/widget_location_sharing_off_night"
|
||||
android:duration="500" />
|
||||
</animation-list>
|
10
OsmAnd/res/drawable/anim_widget_location_sharing_on_day.xml
Normal file
10
OsmAnd/res/drawable/anim_widget_location_sharing_on_day.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:oneshot="false">
|
||||
<item
|
||||
android:drawable="@drawable/widget_location_sharing_on_day"
|
||||
android:duration="500" />
|
||||
<item
|
||||
android:drawable="@drawable/widget_location_sharing_off_day"
|
||||
android:duration="500" />
|
||||
</animation-list>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:oneshot="false">
|
||||
<item
|
||||
android:drawable="@drawable/widget_location_sharing_on_night"
|
||||
android:duration="500" />
|
||||
<item
|
||||
android:drawable="@drawable/widget_location_sharing_off_night"
|
||||
android:duration="500" />
|
||||
</animation-list>
|
|
@ -3,6 +3,7 @@ package net.osmand.plus.views.mapwidgets;
|
|||
import android.app.Activity;
|
||||
import android.graphics.Paint.Style;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.AnimationDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Gravity;
|
||||
|
@ -71,6 +72,10 @@ public class TextInfoWidget {
|
|||
public void setImageDrawable(Drawable imageDrawable, boolean gone) {
|
||||
if(imageDrawable != null) {
|
||||
imageView.setImageDrawable(imageDrawable);
|
||||
Object anim = imageView.getDrawable();
|
||||
if (anim instanceof AnimationDrawable) {
|
||||
((AnimationDrawable) anim).start();
|
||||
}
|
||||
imageView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
imageView.setVisibility(gone ? View.GONE : View.INVISIBLE);
|
||||
|
|
Loading…
Reference in a new issue