Merge pull request #8185 from osmandapp/Widget_for_Tracker_in_OsmAnd

Widget for tracker in osm and
This commit is contained in:
max-klaus 2020-01-08 14:04:32 +03:00 committed by GitHub
commit a6300d5c3d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 157 additions and 0 deletions

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <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_descr">Maximum time to store points in the buffer</string>
<string name="buffer_time">Buffer expiration time</string> <string name="buffer_time">Buffer expiration time</string>
<string name="time_zone_descr">Select time zone to show in your location messages.</string> <string name="time_zone_descr">Select time zone to show in your location messages.</string>

View file

@ -56,6 +56,7 @@ class TelegramApplication : Application(), OsmandHelperListener {
) )
showLocationHelper.addDirectionContextMenuButton() showLocationHelper.addDirectionContextMenuButton()
showLocationHelper.startShowingLocation() showLocationHelper.startShowingLocation()
showLocationHelper.addOrUpdateStatusWidget(-1, false)
} }
} }
} }

View file

@ -20,12 +20,15 @@ import net.osmand.telegram.utils.AndroidUtils
import org.drinkless.td.libcore.telegram.TdApi import org.drinkless.td.libcore.telegram.TdApi
import java.util.* 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_MESSAGES_INTERVAL_MS = 10000L // 10 sec
private const val UPDATE_LIVE_TRACKS_INTERVAL_MS = 30000L // 30 sec private const val UPDATE_LIVE_TRACKS_INTERVAL_MS = 30000L // 30 sec
class TelegramService : Service(), LocationListener, TelegramIncomingMessagesListener, class TelegramService : Service(), LocationListener, TelegramIncomingMessagesListener,
TelegramOutgoingMessagesListener { TelegramOutgoingMessagesListener {
private val log = PlatformUtil.getLog(TelegramService::class.java)
private fun app() = application as TelegramApplication private fun app() = application as TelegramApplication
private val binder = LocationServiceBinder() private val binder = LocationServiceBinder()
private var shouldCleanupResources: Boolean = false private var shouldCleanupResources: Boolean = false
@ -36,6 +39,9 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
private var updateTracksHandler: Handler? = null private var updateTracksHandler: Handler? = null
private var tracksHandlerThread = HandlerThread("TracksUpdateServiceThread") private var tracksHandlerThread = HandlerThread("TracksUpdateServiceThread")
private var updateWidgetHandler: Handler? = null
private var updateWidgetThread = HandlerThread("WidgetUpdateServiceThread")
var handler: Handler? = null var handler: Handler? = null
private set private set
var usedBy = 0 var usedBy = 0
@ -58,8 +64,10 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
super.onCreate() super.onCreate()
mHandlerThread.start() mHandlerThread.start()
tracksHandlerThread.start() tracksHandlerThread.start()
updateWidgetThread.start()
updateShareInfoHandler = Handler(mHandlerThread.looper) updateShareInfoHandler = Handler(mHandlerThread.looper)
updateTracksHandler = Handler(tracksHandlerThread.looper) updateTracksHandler = Handler(tracksHandlerThread.looper)
updateWidgetHandler = Handler(updateWidgetThread.looper)
} }
override fun onBind(intent: Intent): IBinder? { override fun onBind(intent: Intent): IBinder? {
@ -106,6 +114,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
if (isUsedByMyLocation(usedBy)) { if (isUsedByMyLocation(usedBy)) {
initLocationUpdates() initLocationUpdates()
startShareInfoUpdates() startShareInfoUpdates()
startWidgetUpdates()
} }
if (isUsedByUsersLocations(usedBy)) { if (isUsedByUsersLocations(usedBy)) {
app.telegramHelper.startLiveMessagesUpdates(app.settings.sendMyLocInterval) app.telegramHelper.startLiveMessagesUpdates(app.settings.sendMyLocInterval)
@ -139,6 +148,8 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
app.telegramService = null app.telegramService = null
tracksHandlerThread.quit() tracksHandlerThread.quit()
mHandlerThread.quit() mHandlerThread.quit()
updateWidgetThread.quit()
app().showLocationHelper.addOrUpdateStatusWidget(-1, false)
usedBy = 0 usedBy = 0
@ -210,6 +221,33 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
}, UPDATE_LIVE_TRACKS_INTERVAL_MS) }, 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") @SuppressLint("MissingPermission")
private fun getFirstTimeRunDefaultLocation(): net.osmand.Location? { private fun getFirstTimeRunDefaultLocation(): net.osmand.Location? {
val app = app() val app = app()

View file

@ -43,6 +43,15 @@ class ShowLocationHelper(private val app: TelegramApplication) {
const val GPX_COLORS_COUNT = 10 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( val GPX_COLORS = arrayOf(
"red", "orange", "lightblue", "blue", "purple", "red", "orange", "lightblue", "blue", "purple",
"translucent_red", "translucent_orange", "translucent_lightblue", "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? { private fun getALatLonFromMessage(content: TdApi.MessageContent): ALatLon? {
return when (content) { return when (content) {
is TdApi.MessageLocation -> ALatLon(content.location.latitude, content.location.longitude) is TdApi.MessageLocation -> ALatLon(content.location.latitude, content.location.longitude)

View file

@ -45,6 +45,18 @@ object OsmandFormatter {
fixed2.minimumIntegerDigits = 1 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 { fun getFormattedDuration(ctx: Context, seconds: Long, short: Boolean = false): String {
val hours = seconds / (60 * 60) val hours = seconds / (60 * 60)
val minutes = seconds / 60 % 60 val minutes = seconds / 60 % 60

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

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

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

View 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_night"
android:duration="500" />
<item
android:drawable="@drawable/widget_location_sharing_off_night"
android:duration="500" />
</animation-list>

View file

@ -3,6 +3,7 @@ package net.osmand.plus.views.mapwidgets;
import android.app.Activity; import android.app.Activity;
import android.graphics.Paint.Style; import android.graphics.Paint.Style;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.Gravity; import android.view.Gravity;
@ -71,6 +72,10 @@ public class TextInfoWidget {
public void setImageDrawable(Drawable imageDrawable, boolean gone) { public void setImageDrawable(Drawable imageDrawable, boolean gone) {
if(imageDrawable != null) { if(imageDrawable != null) {
imageView.setImageDrawable(imageDrawable); imageView.setImageDrawable(imageDrawable);
Object anim = imageView.getDrawable();
if (anim instanceof AnimationDrawable) {
((AnimationDrawable) anim).start();
}
imageView.setVisibility(View.VISIBLE); imageView.setVisibility(View.VISIBLE);
} else { } else {
imageView.setVisibility(gone ? View.GONE : View.INVISIBLE); imageView.setVisibility(gone ? View.GONE : View.INVISIBLE);