diff --git a/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java b/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java
index b2cef88e80..bee9fa2b19 100644
--- a/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java
+++ b/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java
@@ -1790,6 +1790,7 @@ public class GPXUtilities {
serializer.attribute(null, "creator", file.author); //$NON-NLS-1$
}
serializer.attribute(null, "xmlns", "http://www.topografix.com/GPX/1/1"); //$NON-NLS-1$ //$NON-NLS-2$
+ serializer.attribute(null, "xmlns:osmand", "https://osmand.net");
serializer.attribute(null, "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
serializer.attribute(null, "xsi:schemaLocation",
"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd");
@@ -1938,7 +1939,7 @@ public class GPXUtilities {
serializer.startTag(null, "extensions");
if (!extensions.isEmpty()) {
for (Entry s : extensions.entrySet()) {
- writeNotNullText(serializer, s.getKey(), s.getValue());
+ writeNotNullText(serializer,"osmand:" + s.getKey(), s.getValue());
}
}
if (extensionsWriter != null) {
diff --git a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java
index 5c2faf0b51..d00bf9ffb2 100644
--- a/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java
+++ b/OsmAnd-java/src/main/java/net/osmand/search/core/SearchCoreFactory.java
@@ -719,9 +719,10 @@ public class SearchCoreFactory {
results.put(res.pt.getKeyName(), res);
}
}
- if (nmAdditional != null) {
- addAditonals(nmAdditional, results, types.getOtherMapCategory());
- }
+ // don't spam results with unsearchable additionals like 'description', 'email', ...
+ // if (nmAdditional != null) {
+ // addAditonals(nmAdditional, results, types.getOtherMapCategory());
+ // }
for (PoiCategory c : categories) {
PoiTypeResult res = checkPoiType(nm, c);
if(res != null) {
diff --git a/OsmAnd-java/src/main/java/net/osmand/util/GeoPointParserUtil.java b/OsmAnd-java/src/main/java/net/osmand/util/GeoPointParserUtil.java
index 951ae870e2..3906aff004 100644
--- a/OsmAnd-java/src/main/java/net/osmand/util/GeoPointParserUtil.java
+++ b/OsmAnd-java/src/main/java/net/osmand/util/GeoPointParserUtil.java
@@ -553,11 +553,20 @@ public class GeoPointParserUtil {
}
if (searchRequest != null) {
+ String searchPattern = Pattern.compile("(?:\\.|,|\\s+|\\+|[+-]?\\d+(?:\\.\\d+)?)").pattern();
+ String[] search = searchRequest.split(searchPattern);
+ if (search.length > 0) {
+ return new GeoParsedPoint(searchRequest);
+ }
final Matcher positionInSearchRequestMatcher =
positionPattern.matcher(searchRequest);
if (lat == 0.0 && lon == 0.0 && positionInSearchRequestMatcher.find()) {
- lat = Double.valueOf(positionInSearchRequestMatcher.group(1));
- lon = Double.valueOf(positionInSearchRequestMatcher.group(2));
+ double tempLat = Double.valueOf(positionInSearchRequestMatcher.group(1));
+ double tempLon = Double.valueOf(positionInSearchRequestMatcher.group(2));
+ if (tempLat >= -90 && tempLat <= 90 && tempLon >= -180 && tempLon <= 180) {
+ lat = tempLat;
+ lon = tempLon;
+ }
}
}
diff --git a/OsmAnd-telegram/AndroidManifest.xml b/OsmAnd-telegram/AndroidManifest.xml
index 73e2e856ca..625e51ee8e 100644
--- a/OsmAnd-telegram/AndroidManifest.xml
+++ b/OsmAnd-telegram/AndroidManifest.xml
@@ -7,9 +7,7 @@
-
-
+ android:theme="@style/AppTheme"
+ android:hasFragileUserData="true"
+ android:requestLegacyExternalStorage="true">
+
-
-
-
-
-
-
-
-
- Endre batterioptimiseringsinnstillinger for mer stabil posisjonsdeling.
+ Endre batterioptimaliseringsinnstillinger for mer stabil posisjonsdeling.
Bakgrunnsarbeid
- Skru av batterioptimisering for OsmAnd-sporeren slik at det ikke plutselig skrur seg av når det er i bakgrunnen.
+ Skru av batterioptimalisering for OsmAnd-sporeren slik at det ikke plutselig skrur seg av når det er i bakgrunnen.
Deling i bakgrunnen
Gå til innstillinger
Senere
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/OnTelegramServiceAlarmReceiver.kt b/OsmAnd-telegram/src/net/osmand/telegram/OnTelegramServiceAlarmReceiver.kt
deleted file mode 100644
index ee2851dcb6..0000000000
--- a/OsmAnd-telegram/src/net/osmand/telegram/OnTelegramServiceAlarmReceiver.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package net.osmand.telegram
-
-import android.annotation.SuppressLint
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.location.LocationManager
-import net.osmand.telegram.utils.AndroidUtils
-
-class OnTelegramServiceAlarmReceiver : BroadcastReceiver() {
- @SuppressLint("MissingPermission")
- override fun onReceive(context: Context, intent: Intent) {
- val lock = TelegramService.getLock(context)
- val app = context.applicationContext as TelegramApplication
- val service = app.telegramService
- // do not do nothing
- if (lock.isHeld || service == null) {
- return
- }
- lock.acquire(15 * 60 * 1000L)
-
- // request location updates
- val locationManager = service.getSystemService(Context.LOCATION_SERVICE) as LocationManager
- try {
- if (AndroidUtils.isLocationPermissionAvailable(app)) {
- locationManager.requestLocationUpdates(service.serviceOffProvider, 0, 0f, service)
- }
- val handler = service.handler
- if (service.serviceOffInterval > service.serviceErrorInterval && handler != null) {
- handler.postDelayed({
- // if lock is not anymore held
- if (lock.isHeld) {
- lock.release()
- locationManager.removeUpdates(service)
- }
- }, service.serviceErrorInterval)
- }
- } catch (e: RuntimeException) {
- e.printStackTrace()
- }
- }
-}
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/TelegramApplication.kt b/OsmAnd-telegram/src/net/osmand/telegram/TelegramApplication.kt
index b6927dc610..79847600d3 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/TelegramApplication.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/TelegramApplication.kt
@@ -8,12 +8,13 @@ import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.os.Build
import android.os.Handler
+import androidx.core.content.ContextCompat
import net.osmand.PlatformUtil
-import net.osmand.telegram.ui.TrackerLogcatActivity
import net.osmand.telegram.helpers.*
import net.osmand.telegram.helpers.OsmandAidlHelper.OsmandHelperListener
import net.osmand.telegram.helpers.OsmandAidlHelper.UpdatesListener
import net.osmand.telegram.notifications.NotificationHelper
+import net.osmand.telegram.ui.TrackerLogcatActivity
import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.UiUtils
import java.io.File
@@ -146,35 +147,23 @@ class TelegramApplication : Application() {
return internetConnectionAvailable
}
- private fun startTelegramService(intent: Int, serviceOffInterval: Long = 0) {
+ private fun startTelegramService(intent: Int) {
+ /*
var i = intent
- var interval = serviceOffInterval
val serviceIntent = Intent(this, TelegramService::class.java)
-
val telegramService = telegramService
if (telegramService != null) {
i = intent or telegramService.usedBy
- interval = if (TelegramService.isOffIntervalDepended(intent)) {
- Math.min(telegramService.serviceOffInterval, interval)
- } else {
- telegramService.serviceOffInterval
- }
telegramService.stopSelf()
}
-
serviceIntent.putExtra(TelegramService.USAGE_INTENT, i)
- serviceIntent.putExtra(TelegramService.USAGE_OFF_INTERVAL, interval)
serviceIntent.putExtra(TelegramService.SEND_LOCATION_INTERVAL, settings.sendMyLocInterval)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- startForegroundService(serviceIntent)
- } else {
- startService(serviceIntent)
- }
+ ContextCompat.startForegroundService(this, serviceIntent)
+ */
}
fun startMyLocationService() {
- val interval = settings.sendMyLocInterval
- startTelegramService(TelegramService.USED_BY_MY_LOCATION, TelegramService.normalizeOffInterval(interval))
+ startTelegramService(TelegramService.USED_BY_MY_LOCATION)
}
fun stopMyLocationService() {
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/TelegramLocationProvider.kt b/OsmAnd-telegram/src/net/osmand/telegram/TelegramLocationProvider.kt
index d0f283df01..55c1911caf 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/TelegramLocationProvider.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/TelegramLocationProvider.kt
@@ -54,34 +54,6 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
private var agpsDataLastTimeDownloaded: Long = 0
private val useMagneticFieldSensorCompass = false
- // note, passive provider is from API_LEVEL 8 but it is a constant, we can check for it.
- // constant should not be changed in future
- // LocationManager.PASSIVE_PROVIDER
- // put passive provider to first place
- // find location
- val firstTimeRunDefaultLocation: net.osmand.Location?
- @SuppressLint("MissingPermission")
- get() {
- if (!AndroidUtils.isLocationPermissionAvailable(app)) {
- return null
- }
- val service = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
- val ps = service.getProviders(true) ?: return null
- val providers = ArrayList(ps)
- val passiveFirst = providers.indexOf("passive")
- if (passiveFirst > -1) {
- providers.add(0, providers.removeAt(passiveFirst))
- }
- for (provider in providers) {
- val location = convertLocation(service.getLastKnownLocation(provider))
- if (location != null) {
- return location
- }
- }
- return null
- }
-
-
private val gpsListener = object : LocationListener {
override fun onLocationChanged(location: Location?) {
if (location != null) {
@@ -115,6 +87,7 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
@SuppressLint("MissingPermission")
fun resumeAllUpdates() {
+ /*
val service = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
if (app.isInternetConnectionAvailable) {
if (System.currentTimeMillis() - agpsDataLastTimeDownloaded > AGPS_TO_REDOWNLOAD) {
@@ -162,11 +135,12 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
}
}
-
+ */
registerOrUnregisterCompassListener(true)
}
- fun redownloadAGPS() {
+ private fun redownloadAGPS() {
+ /*
try {
val service = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
service.sendExtraCommand(LocationManager.GPS_PROVIDER, "delete_aiding_data", null)
@@ -178,7 +152,7 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
agpsDataLastTimeDownloaded = 0L
e.printStackTrace()
}
-
+ */
}
private fun getGpsStatusListener(service: LocationManager): GpsStatus.Listener {
@@ -245,6 +219,7 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
@Synchronized
fun registerOrUnregisterCompassListener(register: Boolean) {
+ /*
if (sensorRegistered && !register) {
Log.d(PlatformUtil.TAG, "Disable sensor") //$NON-NLS-1$
(app.getSystemService(Context.SENSOR_SERVICE) as SensorManager).unregisterListener(this)
@@ -285,6 +260,7 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
}
sensorRegistered = true
}
+ */
}
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
@@ -418,12 +394,14 @@ class TelegramLocationProvider(private val app: TelegramApplication) : SensorEve
}
private fun stopLocationRequests() {
+ /*
val service = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
service.removeGpsStatusListener(gpsStatusListener)
service.removeUpdates(gpsListener)
while (!networkListeners.isEmpty()) {
service.removeUpdates(networkListeners.poll())
}
+ */
}
fun pauseAllUpdates() {
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/TelegramService.kt b/OsmAnd-telegram/src/net/osmand/telegram/TelegramService.kt
index ee05034cb7..c3dde54e76 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/TelegramService.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/TelegramService.kt
@@ -1,16 +1,14 @@
package net.osmand.telegram
import android.annotation.SuppressLint
-import android.app.AlarmManager
-import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
+import android.content.pm.ServiceInfo
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.*
-import android.util.Log
import android.widget.Toast
import net.osmand.PlatformUtil
import net.osmand.telegram.TelegramSettings.ShareChatInfo
@@ -26,7 +24,7 @@ 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 {
+ TelegramOutgoingMessagesListener {
private val log = PlatformUtil.getLog(TelegramService::class.java)
@@ -43,21 +41,14 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
private var updateWidgetHandler: Handler? = null
private var updateWidgetThread = HandlerThread("WidgetUpdateServiceThread")
- var handler: Handler? = null
- private set
var usedBy = 0
private set
var serviceOffProvider: String = LocationManager.GPS_PROVIDER
private set
- var serviceOffInterval = 0L
- private set
- var serviceErrorInterval = 0L
- private set
var sendLocationInterval = 0L
private set
private var lastLocationSentTime = 0L
- private var pendingIntent: PendingIntent? = null
class LocationServiceBinder : Binder()
@@ -71,7 +62,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
updateWidgetHandler = Handler(updateWidgetThread.looper)
}
- override fun onBind(intent: Intent): IBinder? {
+ override fun onBind(intent: Intent): IBinder {
return binder
}
@@ -86,13 +77,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
ctx.stopService(serviceIntent)
}
isUsedByMyLocation(usedBy) -> {
- val app = app()
- if (app.settings.sendMyLocInterval >= OFF_INTERVAL_THRESHOLD && serviceOffInterval == 0L) {
- serviceOffInterval = app.settings.sendMyLocInterval
- setupServiceErrorInterval()
- setupAlarm()
- }
- app.notificationHelper.refreshNotification(NotificationType.LOCATION)
+ app().notificationHelper.refreshNotification(NotificationType.LOCATION)
}
isUsedByUsersLocations(usedBy) -> removeLocationUpdates()
}
@@ -100,19 +85,21 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
val app = app()
- handler = Handler()
val usageIntent = intent.getIntExtra(USAGE_INTENT, 0)
usedBy = usageIntent or usedBy
- serviceOffInterval = intent.getLongExtra(USAGE_OFF_INTERVAL, 0)
sendLocationInterval = intent.getLongExtra(SEND_LOCATION_INTERVAL, 0)
- setupServiceErrorInterval()
app.telegramHelper.addIncomingMessagesListener(this)
app.telegramHelper.addOutgoingMessagesListener(this)
app.telegramService = this
+ val locationNotification = app.notificationHelper.locationNotification
+ val notification = app.notificationHelper.buildNotification(locationNotification)
+ startForeground(locationNotification.telegramNotificationId, notification)
+ app.notificationHelper.refreshNotification(locationNotification.type)
+
if (isUsedByMyLocation(usedBy)) {
initLocationUpdates()
startShareInfoUpdates()
@@ -124,21 +111,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
}
app.shareLocationHelper.checkAndSendBufferMessages()
- val locationNotification = app.notificationHelper.locationNotification
- val notification = app.notificationHelper.buildNotification(locationNotification)
- startForeground(locationNotification.telegramNotificationId, notification)
- app.notificationHelper.refreshNotification(locationNotification.type)
- return Service.START_REDELIVER_INTENT
- }
-
- private fun setupServiceErrorInterval() {
- serviceErrorInterval = serviceOffInterval / 5
- // 1. not more than 12 mins
- serviceErrorInterval = Math.min(serviceErrorInterval, 12 * 60 * 1000)
- // 2. not less than 30 seconds
- serviceErrorInterval = Math.max(serviceErrorInterval, 30 * 1000)
- // 3. not more than serviceOffInterval
- serviceErrorInterval = Math.min(serviceErrorInterval, serviceOffInterval)
+ return START_REDELIVER_INTENT
}
override fun onDestroy() {
@@ -158,13 +131,6 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
removeLocationUpdates()
- if (!isContinuous()) {
- val lock = getLock(this)
- if (lock.isHeld) {
- lock.release()
- }
- }
-
if (shouldCleanupResources) {
app.cleanupResources()
}
@@ -176,7 +142,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
fun updateSendLocationInterval(newInterval: Long) {
sendLocationInterval = newInterval
}
-
+
fun forceLocationUpdate() {
val location = getFirstTimeRunDefaultLocation()
app().shareLocationHelper.updateLocation(location)
@@ -186,22 +152,19 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
val firstLocation = getFirstTimeRunDefaultLocation()
app().shareLocationHelper.updateLocation(firstLocation)
- // requesting
- if (isContinuous()) {
- // request location updates
- val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
- try {
- locationManager.requestLocationUpdates(serviceOffProvider, 0, 0f, this@TelegramService)
- } catch (e: SecurityException) {
- Toast.makeText(this, R.string.no_location_permission, Toast.LENGTH_LONG).show()
- Log.d(PlatformUtil.TAG, "Location service permission not granted") //$NON-NLS-1$
- } catch (e: IllegalArgumentException) {
- Toast.makeText(this, R.string.gps_not_available, Toast.LENGTH_LONG).show()
- Log.d(PlatformUtil.TAG, "GPS location provider not available") //$NON-NLS-1$
- }
- } else {
- setupAlarm()
+ // request location updates
+ /*
+ val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
+ try {
+ locationManager.requestLocationUpdates(serviceOffProvider, 0, 0f, this@TelegramService)
+ } catch (e: SecurityException) {
+ Toast.makeText(this, R.string.no_location_permission, Toast.LENGTH_LONG).show()
+ log.debug("Location service permission not granted")
+ } catch (e: IllegalArgumentException) {
+ Toast.makeText(this, R.string.gps_not_available, Toast.LENGTH_LONG).show()
+ log.debug("GPS location provider not available")
}
+ */
}
private fun startShareInfoUpdates() {
@@ -254,13 +217,15 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
startWidgetUpdates()
}, UPDATE_WIDGET_INTERVAL_MS)
}
-
+
@SuppressLint("MissingPermission")
private fun getFirstTimeRunDefaultLocation(): net.osmand.Location? {
val app = app()
if (!AndroidUtils.isLocationPermissionAvailable(app)) {
return null
}
+ var location: net.osmand.Location? = null
+ /*
val service = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val ps = service.getProviders(true) ?: return null
val providers = ArrayList(ps)
@@ -272,53 +237,31 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
providers.add(0, providers.removeAt(passiveFirst))
}
// find location
- var location: net.osmand.Location? = null
for (provider in providers) {
val loc = convertLocation(service.getLastKnownLocation(provider))
if (loc != null && (location == null || loc.hasAccuracy() && loc.accuracy < location.accuracy)) {
location = loc
}
}
+ */
return location
}
- private fun setupAlarm() {
- val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
- pendingIntent = PendingIntent.getBroadcast(this, 0, Intent(this, OnTelegramServiceAlarmReceiver::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
- alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 500, serviceOffInterval, pendingIntent)
- }
-
private fun removeLocationUpdates() {
// remove updates
+ /*
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
try {
locationManager.removeUpdates(this)
} catch (e: SecurityException) {
- Log.d(PlatformUtil.TAG, "Location service permission not granted")
+ log.debug("Location service permission not granted")
}
- }
-
- private fun isContinuous(): Boolean {
- return serviceOffInterval == 0L
+ */
}
override fun onLocationChanged(l: Location?) {
val location = convertLocation(l)
- if (!isContinuous()) {
- // unregister listener and wait next time
- val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
- try {
- locationManager.removeUpdates(this)
- } catch (e: Throwable) {
- Log.d(PlatformUtil.TAG, "Location service permission not granted") //$NON-NLS-1$
- }
-
- val lock = getLock(this)
- if (lock.isHeld) {
- lock.release()
- }
- app().shareLocationHelper.updateLocation(location)
- } else if (System.currentTimeMillis() - lastLocationSentTime > sendLocationInterval * 1000) {
+ if (System.currentTimeMillis() - lastLocationSentTime > sendLocationInterval * 1000) {
lastLocationSentTime = System.currentTimeMillis()
app().shareLocationHelper.updateLocation(location)
}
@@ -373,7 +316,7 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
}
override fun onSendLiveLocationError(code: Int, message: String, shareInfo: ShareChatInfo, messageType: Int) {
- Log.d(PlatformUtil.TAG, "Send live location error: $code - $message")
+ log.debug("Send live location error: $code - $message")
when (messageType) {
TelegramHelper.MESSAGE_TYPE_TEXT -> shareInfo.pendingTdLibText--
TelegramHelper.MESSAGE_TYPE_MAP -> {
@@ -388,26 +331,8 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
const val USED_BY_MY_LOCATION: Int = 1
const val USED_BY_USERS_LOCATIONS: Int = 2
const val USAGE_INTENT = "SERVICE_USED_BY"
- const val USAGE_OFF_INTERVAL = "SERVICE_OFF_INTERVAL"
const val SEND_LOCATION_INTERVAL = "SEND_LOCATION_INTERVAL"
- const val OFF_INTERVAL_THRESHOLD: Long = 30000L
-
- private var lockStatic: PowerManager.WakeLock? = null
-
- @Synchronized
- fun getLock(context: Context): PowerManager.WakeLock {
- var lockStatic = lockStatic
- return if (lockStatic == null) {
- val mgr = context.getSystemService(Context.POWER_SERVICE) as PowerManager
- lockStatic = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "OsmandServiceLock")
- this.lockStatic = lockStatic
- lockStatic
- } else {
- lockStatic
- }
- }
-
fun isUsedByMyLocation(usedBy: Int): Boolean {
return (usedBy and USED_BY_MY_LOCATION) > 0
}
@@ -416,14 +341,6 @@ class TelegramService : Service(), LocationListener, TelegramIncomingMessagesLis
return (usedBy and USED_BY_USERS_LOCATIONS) > 0
}
- fun isOffIntervalDepended(usedBy: Int): Boolean {
- return isUsedByMyLocation(usedBy)
- }
-
- fun normalizeOffInterval(interval: Long): Long {
- return if (interval < OFF_INTERVAL_THRESHOLD) 0 else interval
- }
-
fun convertLocation(l: Location?): net.osmand.Location? {
if (l == null) {
return null
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt
index efdb35edf1..bece18b8f4 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt
@@ -505,6 +505,8 @@ class TelegramSettings(private val app: TelegramApplication) {
val currentTimeMillis = System.currentTimeMillis()
val currentTime = currentTimeMillis / 1000
statusChangeTime = currentTimeMillis
+ val gpsEnabled = false
+ /*
val lm = app.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val gpsEnabled = try {
if (lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
@@ -518,6 +520,7 @@ class TelegramSettings(private val app: TelegramApplication) {
} catch (ex: Exception) {
false
}
+ */
var initializing = false
var sendChatsErrors = false
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt
index fee5d83151..7d87ce3b1d 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt
@@ -21,7 +21,6 @@ import android.widget.*
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.appbar.AppBarLayout
import net.osmand.PlatformUtil
import net.osmand.telegram.*
@@ -42,7 +41,7 @@ private const val SUGGESTED = 2
private const val SHARE_LOCATION_CHAT = 1
private const val DEFAULT_CHAT = 0
-private const val ADAPTER_UPDATE_INTERVAL_MIL = 5 * 1000L // 5 sec
+private const val ADAPTER_UPDATE_INTERVAL_MS = 5 * 1000L // 5 sec
class MyLocationTabFragment : Fragment(), TelegramListener {
@@ -380,7 +379,7 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
updateContent()
startHandler()
}
- }, ADAPTER_UPDATE_INTERVAL_MIL)
+ }, ADAPTER_UPDATE_INTERVAL_MS)
}
private fun animateStartSharingBtn(show: Boolean) {
diff --git a/OsmAnd/build.gradle b/OsmAnd/build.gradle
index 8552c2b293..a3f80f4c46 100644
--- a/OsmAnd/build.gradle
+++ b/OsmAnd/build.gradle
@@ -287,7 +287,6 @@ task collectHelpContentsAssets(type: Copy) {
include "about.html"
include "changes.html"
include "faq.html"
- include "technical-articles.html"
include "map-legend.html"
}
from("../../help/website/feature_articles") {
diff --git a/OsmAnd/build.gradle.lib b/OsmAnd/build.gradle.lib
index b5fd457270..6b0f4da990 100644
--- a/OsmAnd/build.gradle.lib
+++ b/OsmAnd/build.gradle.lib
@@ -174,7 +174,6 @@ task collectHelpContentsAssets(type: Copy) {
include "about.html"
include "changes.html"
include "faq.html"
- include "technical-articles.html"
include "map-legend.html"
}
from("../../help/website/feature_articles") {
diff --git a/OsmAnd/res/drawable/ic_action_name_field.xml b/OsmAnd/res/drawable/ic_action_name_field.xml
new file mode 100644
index 0000000000..5c340db2c2
--- /dev/null
+++ b/OsmAnd/res/drawable/ic_action_name_field.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/OsmAnd/res/drawable/ic_overflow_menu_with_background.xml b/OsmAnd/res/drawable/ic_overflow_menu_with_background.xml
new file mode 100644
index 0000000000..d79b484f72
--- /dev/null
+++ b/OsmAnd/res/drawable/ic_overflow_menu_with_background.xml
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/OsmAnd/res/drawable/img_help_announcement_time_day.xml b/OsmAnd/res/drawable/img_help_announcement_time_day.xml
new file mode 100644
index 0000000000..e6bca9e5a1
--- /dev/null
+++ b/OsmAnd/res/drawable/img_help_announcement_time_day.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OsmAnd/res/drawable/img_help_announcement_time_night.xml b/OsmAnd/res/drawable/img_help_announcement_time_night.xml
new file mode 100644
index 0000000000..5a4ad0251e
--- /dev/null
+++ b/OsmAnd/res/drawable/img_help_announcement_time_night.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OsmAnd/res/layout/bottom_sheet_item_title_with_description.xml b/OsmAnd/res/layout/bottom_sheet_item_title_with_description.xml
new file mode 100644
index 0000000000..9ffaa2e9dd
--- /dev/null
+++ b/OsmAnd/res/layout/bottom_sheet_item_title_with_description.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OsmAnd/res/layout/bottom_sheet_item_with_descr_radio_and_icon_btn.xml b/OsmAnd/res/layout/bottom_sheet_item_with_descr_radio_and_icon_btn.xml
index d81614fbb1..c4dc6d4265 100644
--- a/OsmAnd/res/layout/bottom_sheet_item_with_descr_radio_and_icon_btn.xml
+++ b/OsmAnd/res/layout/bottom_sheet_item_with_descr_radio_and_icon_btn.xml
@@ -14,10 +14,11 @@
android:orientation="horizontal">
+ app:srcCompat="@drawable/ic_action_settings" />
diff --git a/OsmAnd/res/layout/select_folder_row.xml b/OsmAnd/res/layout/select_folder_row.xml
new file mode 100644
index 0000000000..d9340cc5f2
--- /dev/null
+++ b/OsmAnd/res/layout/select_folder_row.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OsmAnd/res/values-cs/strings.xml b/OsmAnd/res/values-cs/strings.xml
index 3159e5591a..593c4d3bc9 100644
--- a/OsmAnd/res/values-cs/strings.xml
+++ b/OsmAnd/res/values-cs/strings.xml
@@ -275,7 +275,7 @@
Nastavte průhlednost (0 - průhledný, 255 - neprůhledný)
Podkladová mapa…
Podkresová mapa
- Vyberte podkladovou mapu.
+ Vyberte podkladovou mapu
Překryvná mapa…
Žádná
Překryvná mapa
@@ -309,7 +309,9 @@
Sdílet polohu
GPX bod na trase \'\'{0}\'\' byl přidán
Přidat bod na zaznamenávanou GPX trasu
- Off-line navigace je experimentální a funguje jen pro větší vzdálenosti než 20 km. Navigace je dočasně přepnuta na on-line CloudMade.
+ Off-line navigace je experimentální a funguje jen pro větší vzdálenosti než 20 km.
+\n
+\nNavigace je dočasně přepnuta na online službu CloudMade.
Nepodařilo se najít zadaný adresář.
Adresář pro data
Aplikace pro zobrazení stavu GPS není nainstalovaná. Hledat v obchodě?
@@ -440,7 +442,7 @@
Na šířku
Orientace obrazovky
Orientace obrazovky: na výšku, na šířku, podle zařízení.
- Formát otevírací doby nemůže být změněn
+ Formát otevírací doby nemůže být změněn.
Přidat nové pravidlo
Cesty
Zastávka
@@ -459,8 +461,8 @@
Zobrazit zastávky
Navigační aplikace OsmAnd
Data POI byla aktualizována ({0} načteno)
- Nelze aktualizovat lokální seznam POI
- Nelze načíst data ze serveru
+ Nepodařilo se aktualizovat lokální seznam POI.
+ Nepodařilo se načíst data ze serveru.
Pro tuto oblast nejsou dostupné žádné off-line POI
Větší přiblížení vám umožní aktualizovat POI
Aktualizovat POI
@@ -482,11 +484,11 @@
Hledání off-line
Hledat on-line
Maximální zvětšení
- Nelze procházet dlaždice online map pro přiblížení nad tuto úroveň.
+ Nepoužívat online mapy pro přiblížení nad tuto úroveň.
Celková vzdálenost %1$s, doba cesty %2$d h %3$d min.
- Vyberte online nebo offline navigační službu.
+ Online nebo offline navigační služba.
Navigace
- Úložný datový adresář na paměťové kartě není dostupný!
+ Úložný adresář na paměťové kartě není dostupný!
Stáhnout {0} - {1} ?
Offline data pro {0} již existují ({1}). Aktualizovat je ({2})\?
Adresa
@@ -500,7 +502,7 @@
Pouze zobrazit
Spustit navádění
Způsob dopravy:
- Prosím zadejte nejprve cíl
+ Prosím nejprve zadejte cíl
Navigace
Otevírací doba
Otevírání sady změn…
@@ -515,14 +517,14 @@
Načítání ulic…
Načítání měst…
POI
- Nelze uložit soubor GPX
- Nelze vypočítat trasu
- Nelze vypočítat trasu
- Vypočtená trasa je prázdná
+ Nepodařilo se uložit soubor GPX.
+ Nepodařilo se vypočítat trasu.
+ Nepodařilo se vypočítat trasu.
+ Vypočítaná trasa je prázdná.
Vypočtena nová trasa, vzdálenost
- Dorazili jste do cíle
+ Dorazili jste do cíle.
Neplatné souřadnice
- Vrátit se k mapě OsmAnd
+ Vrátit se k mapě
Zavřít
Načítání dat…
Načítání místních dat…
@@ -559,15 +561,15 @@
Zorné pole
Zapnout 3D pohled na mapu.
3D Mapa
- Zobrazit naposledy vybrané POI jako vrstvu na mapě.
+ Zobrazit naposledy použité POI jako vrstvu.
Zobrazit vrstvu POI
- Zvolte zdroj on-line dlaždic nebo dlaždic v mezipaměti.
+ Zvolte zdroj online mapových dlaždic nebo dlaždic v mezipaměti.
Zdroj rastrových map
Zdroj map
Používat Internet
Zobrazit mou polohu
Zobrazit GPS souřadnice na mapě
- Stahovat chybějící části mapy z internetu
+ Stáhnout chybějící mapové dlaždice
Navigační aplikace
Konec
Hledat
@@ -586,11 +588,11 @@
Chůze
Uprostřed
Dole
- Zadejte zem. šířku a délku ve vybraném formátu (D - stupně, M - minuty, S - vteřiny)
+ Zadejte zeměpisnou šířku a délku ve vybraném formátu (D - stupně, M - minuty, S - vteřiny)
Šířka
Délka
Zobrazit na mapě
- Zvolit adresu
+ Adresa
Oblast
Město
Ulice
@@ -621,7 +623,7 @@
Vymazat {0} (komentář) \?
Vymazat POI
Vymazat
- POI byl vymazán
+ Smazáno
Přidání
Změna
Akce {0} provedena.
@@ -636,9 +638,9 @@
Vyčistit
Filtr
Uložit jako
- Smazat vybraný filtr?
- Filtr %1$s byl smazán
- Filtr %1$s byl vytvořen
+ Smazat tento filtr\?
+ Filtr \'%1$s\' byl smazán
+ Filtr \'%1$s\' byl vytvořen
Off-line navigace OsmAnd je dočasně nedostupná.
Levostranný provoz
Pro země, kde se jezdí po levé straně cesty.
@@ -672,8 +674,8 @@
Kategorie
Správce mapových souborů.
DDD.DDDDD
- DDD MM.MMMMM
- DDD MM SS.SSSSS
+ DDD MM.MMM
+ DDD MM SS.S
Navigační data
Formát
Hledat body zájmu (POI)
@@ -1022,15 +1024,15 @@
Dopravní varování
Heslo OSM (volitelné)
Typ ostření fotoaparátu
- Zvolte způsob ostření vestavěného fotoaparátu.
+ Režim zaostřování fotoaparátu:
Automatické ostření
Fix-focus
Fix-focus
- Ostření na nekonečno
+ Ostření je nastaveno na nekonečno
Makro
Kamera ostří souvisle
Přehrát zvuk závěrky
- Zvolte zda při vyfotografování snímku má být přehrán zvuk závěrky.
+ Nastavit zvuk či ticho při pořízení snímku.
Mezicíle jsou již nastaveny.
Navigovat sem
Navigovat odsud
@@ -1229,8 +1231,7 @@
Uložit jako skupinu Oblíbených
Určete cíle
Překryvné popisky bodů
-
- On-line OSM klasifikace map s obrázky.
+ On-line OSM klasifikace map s obrázky.
Zobrazit tlačítka lupy během navigace.
Zobrazit tlačítka lupy
Třídit podle vzdálenosti
@@ -1287,7 +1288,7 @@
Později
V posledních metrech
Velikost fotografie
- Vyberte velikost obrázku interního fotoaparátu.
+ Nastavte velikost obrázku fotoaparátu
Více…
Standardní
Automobil
@@ -1442,12 +1443,12 @@
Exportovat
Povolit
Zakázat
- Pro instalaci tohoto modulu je potřeba internetové připojení.
+ Pro instalaci tohoto modulu musíte být online.
Získat
Body cesty
Simulovat polohu
Šířka %1$s
-Délka %2$s
+\nDélka %2$s
Nastavení navigace
Všeobecná nastavení
…
@@ -1589,11 +1590,11 @@ Délka %2$s
Přidat otevírací dobu
Kontaktní informace
Máte rádi OsmAnd?
- Záleží nám na vašem názoru, zpětná vazba je pro nás důležitá.
+ Oceníme váš názor a zpětnou vazbu.
Ohodnoťte tuto aplikaci
Ohodnoťte prosím aplikaci OsmAnd na Google Play
Řekněte nám proč.
- Sdělte nám prosím, co byste chtěli v této aplikaci změnit.
+ Sdělte nám prosím své návrhy.
Přeskočit
OsmAnd
Moduly
@@ -1612,7 +1613,7 @@ Délka %2$s
Karta byla skryta
Zpět
Off-line mapy
-& navigace
+\n& navigace
Odeslat POI
Základní
Rozšířené
@@ -1836,7 +1837,7 @@ Délka %2$s
Jednou týdně
Ráno
V noci
- Vyberte měsíc a krajinu
+ Měsíc a země:
Odstranit
Ikony POI
Vybrat
@@ -1918,7 +1919,7 @@ Délka %2$s
Doporučujeme vypnout vykreslování polygonů.
Zobrazit trasy pro horská kola
Aplikace nyní smí zapisovat na externí úložiště, ale je potřeba její restart.
- Název souboru obsahuje nepovolené znaky
+ Nepovolený znak v názvu souboru
Modul usnadnění: Cíl není nastaven
Magnetické směrování
Relativní směrování
@@ -2112,20 +2113,20 @@ Délka %2$s
Opravdu chcete odstranit akci \"%s\"?
Zobrazit dialog Oblíbených
Přednastavení názvu
- Klepnutím na tlačítko akce se přidá mapová značka do středu obrazovky.
- Klepnutím na tlačítko akce se přidá GPX bod trasy na místo ve středu obrazovky.
- Klepnutím na tlačítko akce se přidá audio záznam na místo ve středu obrazovky.
- Klepnutím na tlačítko akce se přidá video záznam na místo ve středu obrazovky.
- Klepnutím na tlačítko akce se přidá foto záznam na místo ve středu obrazovky.
- Klepnutím na tlačítko akce se přidá OSM poznámka na místo ve středu obrazovky.
- Klepnutím na tlačítko akce se přidá POI na místo ve středu obrazovky.
- Klepnutím na tlačítko akce se vypnou nebo zapnou hlasové pokyny během navigace.
- Klepnutím na tlačítko akce se přidá parkovací místo do středu obrazovky.
+ Tlačítko pro přidání mapové značky do středu obrazovky.
+ Tlačítko pro přidání bodu GPX trasy do středu obrazovky.
+ Tlačítko pro přidání zvukové poznámky do středu obrazovky.
+ Tlačítko pro přidání video poznámky do středu obrazovky.
+ Tlačítko pro přidání foto poznámky do středu obrazovky.
+ Tlačítko pro přidání OSM poznámky do středu obrazovky.
+ Tlačítko pro přidání bodu zájmu do středu obrazovky.
+ Tlačítko pro vypnutí nebo zapnutí hlasových pokynů během navigace.
+ Tlačítko pro přidání místa zaparkování do středu obrazovky.
Místo
- Zadaný název rychlé akce je již použit a byl změněn na %1$s z důvodu duplicity.
+ Rychlá akce byla přejmenována na %1$s z důvodu duplicity.
Duplicitní název rychlé akce
- Klepnutím na tlačítko akce se zobrazí nebo skryjí Oblíbená místa na mapě.
- Klepnutím na tlačítko akce se zobrazí nebo skryjí POI na mapě.
+ Tlačítko pro zobrazení nebo skrytí Oblíbených míst na mapě.
+ Tlačítko pro zobrazení nebo skrytí bodů zájmu na mapě.
Zobrazit/skrýt Oblíbená místa
Zobrazit oblíbená místa
Skrýt Oblíbená místa
@@ -2139,7 +2140,7 @@ Délka %2$s
Ponecháte-li prázdné, bude použita adresa nebo název místa.
Tato zpráva je zahrnuta v poli komentáře.
Zpráva
- Vyberte kategorii pro uložení Oblíbeného místa.
+ Kategorie pro uložení Oblíbeného místa:
Vyberte volitelnou kategorii.
Seznam POI
Přidat jednu nebo více kategorií POI pro zobrazení na mapě.
@@ -2155,23 +2156,23 @@ Délka %2$s
Změnit zdroj mapy
Mapové zdroje
Přidat zdroj mapy
- Zdroj mapy se změnil na \"%s\".
+ Zdroj mapy změněn na \"%s\".
Změnit polohu tlačítka
Podržení a potáhnutí tlačítka změní jeho umístění na obrazovce.
Název akce
Neplatný OLC
-
+\n
Krátké OLC
-Prosím uveďte úplný kód
+\nProsím zadejte úplný kód
Platné plné OLC
-Zobrazená oblast: %1$s x %2$s
- " je uložen do "
- Překryvná mapa se změnila na \"%s\".
- Mapa podkladu se změnila na \"%s\".
+\nOdpovídá oblasti: %1$s x %2$s
+ " uložený do "
+ Překryvná mapa změněna na \"%s\".
+ Podkladová mapa změněna na \"%s\".
Při pauze automaticky rozdělovat nahrávky
Začít nový úsek po 6minutové pauze, novou trasu po 2hodinové pauze nebo nový soubor po delší pauze, pokud se změnilo datum.
Zobrazit dočasné okno
- Aktivace tlačítka akce posune seznam na další stranu.
+ Tlačítko pro posunutí seznamu na další stranu.
Zobrazit hloubkové vrstevnice a body.
Námořní hloubkové vrstevnice
Open Location Code (OLC)
@@ -2337,10 +2338,10 @@ Zobrazená oblast: %1$s x %2$s
Měřit vzdálenost
Časový zásobník pro online sledování
Zadejte čas pro podržení pozic k odeslání, pokud není připojení
- Pro zobrazení fotografií z Mapillary potřebujete internetové připojení.
+ Fotografie z Mapillary jsou dostupné pouze online.
Zkusit znovu
Přidat trasový bod
- Uložit trasový bod GPX
+ Uložit bod GPX trasy
Uložit bod trasy
Trasový bod 1
Bod trasy 1
@@ -2564,7 +2565,8 @@ Zobrazená oblast: %1$s x %2$s
\n• Svoji polohu můžete sdílet se svými přáteli
\n• Důležitá místa si můžete uložit do složky \'Moje místa\'
\n• Můžete si vybrat, jak se na mapě budou zobrazovat názvy: V angličtině, v místním jazyce nebo ve fonetickém přepisu
-\n• Zobrazuje specializované online dlaždice, satelitní mapy (z Bingu), různé překryvné informace jako navigační GPX trasy a další vrstvy s volitelnou průhledností
+\n• Zobrazuje specializované online dlaždice, satelitní mapy (z Bingu), různé překryvné informace jako navigační GPX trasy a další vrstvy s volitelnou průhledností
+\n
Lyžování
\nOsmAnd plugin Lyžařský mapový pohled zobrazuje lyžařské trasy podle stupně obtížnosti a také další informace jako polohy vleků a dalších zařízení.
Cyklistika
@@ -2578,11 +2580,13 @@ Zobrazená oblast: %1$s x %2$s
\n• Wikipedie ve vašem zvoleném jazyce vám poskytne mnoho informací při procházce městem
\n• Při pohybu v neznámém městě vám pomůže zobrazování názvů zastávek a tras veřejné dopravy (autobusy, tramvaje, vlaky)
\n• GPS navigace v režimu Pěší vytvoří trasu cest vhodných pro chodce
-\n• Můžete otevřít GPX trasu a následovat ji nebo zaznamenat a sdílet svou vlastní
+\n• Můžete otevřít GPX trasu a následovat ji nebo zaznamenat a sdílet svou vlastní
+\n
Přispějte do OSM
\n• Hlaste chyby v datech
\n•Nahrávejte GPX trasy do OSM přímo z aplikace
-\n• Přidávejte body zájmu a rovnou je nahrávejte do OSM (nebo později, pokud jste zrovna offline)
+\n• Přidávejte body zájmu a rovnou je nahrávejte do OSM (nebo později, pokud jste zrovna offline)
+\n
OsmAnd je aktivně vyvíjený open source software. Do aplikace může každý přispět hlášením chyb, vylepšováním překladů nebo programováním nových funkcí. Projekt je také závislý na finančních příspěvcích pro vývoj a testování nových funkcí.
\n Přibližné pokrytí a kvalita map:
\n • Západní Evropa: ****
@@ -2609,7 +2613,8 @@ Zobrazená oblast: %1$s x %2$s
\n• Volitelné navádění do jízdních pruhů, zobrazení názvů ulic a předpokládaného čas příjezdu
\n• Podporuje mezicíle v itineráři
\n• Automatické přepočítání trasy při odchýlení
-\n• Hledání míst podle adresy, typu (např. restaurace, hotel, čerpací stanice, muzeum) či podle geografických souřadnic
+\n• Hledání míst podle adresy, typu (např. restaurace, hotel, čerpací stanice, muzeum) či podle geografických souřadnic
+\n
Prohlížení mapy
\n • Zobrazení vaší pozice a orientace
\n • Volitelné otáčení podle směru vašeho pohybu (nebo podle kompasu)
@@ -2630,7 +2635,8 @@ Zobrazená oblast: %1$s x %2$s
\n• Volitelné automatické přepínání denního a nočního režimu
\n• Volitelné zobrazení rychlostních limitů s upozorněním při překročení
\n• Volitelné přiblížení mapy v závislosti na rychlosti
-\n• Sdílení polohy s přáteli
+\n• Sdílení polohy s přáteli
+\n
Funkce pro cyklisty a pěší
\n• Zobrazení pěších, turistických a cyklistických tras, skvělé pro venkovní aktivity
\n• Speciální navigační režim a zobrazení pro cyklisty a chodce
@@ -2784,7 +2790,7 @@ Zobrazená oblast: %1$s x %2$s
Průvodce Wikivoyage Vám ukáže nejzajímavější místa planety, přímo v aplikaci OsmAnd a bez nutnosti připojení k internetu.
Čas příjezdu do mezicíle
Do průjezdního bodu
- Klepněte na tlačítko pro vyslechnutí odpovídajícího hlasového pokynu, aby jste zjistili chybné nebo chybějící pokyny.
+ Klepněte na tlačítko pro vyslechnutí odpovídajícího hlasového pokynu, abyste zjistili, zda chybí nebo je chybný
Pro námořní navigaci. Obsahuje bóje, majáky, plavební cesty, mořské cesty a značky, přístavy, námořní služby a hloubkové vrstevnice.
Pro lyžování. Obsahuje sjezdovky, lyžařské vleky, běžkařské trasy atd. Nedůležité objekty jsou na mapě méně výrazné.
Vítejte v otevřené beta verzi
@@ -2843,7 +2849,7 @@ Zobrazená oblast: %1$s x %2$s
Používáte mapu {0}, která běží na aplikaci OsmAnd. Chcete spustit plnou verzi OsmAnd\?
Spustit OsmAnd\?
Guaranština
- Klepnutím na tlačítko akce se přepíná mezi denním a nočním režimem OsmAnd
+ Tlačítko pro přepínání mezi denním a nočním režimem v OsmAnd.
Denní režim
Noční režim
Přepnout denní/noční režim
@@ -2886,7 +2892,7 @@ Zobrazená oblast: %1$s x %2$s
Výjezd na
Vyměnit
Zobrazit/skrýt stopy
- Tlačítko pro zobrazení nebo skrytí vybraných stop na mapě
+ Tlačítko pro zobrazení nebo skrytí vybraných stop na mapě.
Skrýt stopy
Zobrazit stopy
%1$d přenosů
@@ -2965,8 +2971,8 @@ Zobrazená oblast: %1$s x %2$s
\n
\n • Odstraněné analytické moduly Facebook a Firebase z verze zdarma (OsmAnd+ je neobsahoval)
\n "
- Vyhnout se kostkám
- Vyhnout se kočičím hlavám a dlažebním kostkám
+ Žádné dlažební kostky
+ Vyhne se dlažebním kostkám
Stupně
Miliradiány
Úhlová jednotka
@@ -3068,10 +3074,10 @@ Zobrazená oblast: %1$s x %2$s
Zvolte profily, které mají být viditelné v aplikaci.
Profily aplikace
Použít WunderLINQ pro ovládání
- Musíte přidat alespoň jednu položku v nastavení Rychlé akce
- Alpské/sjezdové lyžování
+ Přidejte alespoň jednu položku do seznamu \'Rychlá akce\'
+ Alpské a sjezdové lyžování
Svahy pro alpské nebo sjezdové lyžování a přístup k lyžařským vlekům.
- Běžecké a severské lyžování
+ Běžecké a klasické lyžování
Trasy pro severské nebo běžecké lyžování.
Lyžařské okruhy
Trasy pro lyžařské okruhy.
@@ -3556,7 +3562,7 @@ Zobrazená oblast: %1$s x %2$s
Stopy
Stopy
Stopy
- "Ukládat trasu do GPX souboru"
+ Ukládat trasu do GPX souboru
Trasa ze stopy
Přidat soubory stop
Zjednodušená trasa
@@ -4014,4 +4020,27 @@ Zobrazená oblast: %1$s x %2$s
Povolit říčky a stoky
Povolit občasné vodní cesty
Povolit občasné vodní cesty
+ Časy hlasových pokynů
+ Přidat online navigační službu
+ Upravit online navigační službu
+ Podtyp
+ Vozidlo
+ API klíč
+ URL serveru
+ Zadejte parametr
+ Pokud ne, nechte prázdné
+ Adresa se všemi parametry bude vypadat takto:
+ Vyzkoušet výpočet trasy
+ Řízení vozidla
+ Chůze
+ Kolo
+ Auto
+ Chyba, zkontrolujte parametry
+ Kopírovat adresu
+ Online navigační služba
+ Online navigační služby
+ Složky
+ Zvolte složku
+ Zvolte složku nebo vytvořte novou
+ Prázdné
\ No newline at end of file
diff --git a/OsmAnd/res/values-de/phrases.xml b/OsmAnd/res/values-de/phrases.xml
index bae219d165..8ea147711e 100644
--- a/OsmAnd/res/values-de/phrases.xml
+++ b/OsmAnd/res/values-de/phrases.xml
@@ -108,7 +108,7 @@
Höhleneingang
Friedhof
Ferienhaus
- Ladestation
+ Ladestation;Ladestation für elektische Fahrzeuge;Aufladestation
Drogerie
Schach
Kinderbekleidungsgeschäft
diff --git a/OsmAnd/res/values-de/strings.xml b/OsmAnd/res/values-de/strings.xml
index 4e20ce5f44..786bc89b7b 100644
--- a/OsmAnd/res/values-de/strings.xml
+++ b/OsmAnd/res/values-de/strings.xml
@@ -738,7 +738,7 @@
OpenStreetMap-Bearbeitung
Weitere Einstellungen
Einstellungen
- Karte aktualisieren
+ Aktualisieren
Kartenteile aktualisieren
Ziel
Zu \'Favoriten\' hinzufügen
@@ -4047,4 +4047,11 @@
Subtyp
Leer lassen, wenn kein API-Schlüssel vorhanden
Adresse kopieren
+ Fahren
+ Online Navigationssystem
+ Online Navigationssysteme
+ Ordner
+ Ordner auswählen
+ Ordner auswählen oder neuen hinzufügen
+ Leer
\ No newline at end of file
diff --git a/OsmAnd/res/values-eo/strings.xml b/OsmAnd/res/values-eo/strings.xml
index 604d169270..0509e0d3fd 100644
--- a/OsmAnd/res/values-eo/strings.xml
+++ b/OsmAnd/res/values-eo/strings.xml
@@ -4044,4 +4044,10 @@
Aŭtomobilo
Eraro, rekontrolu parametrojn
Kopii adreson
+ Enreta navigilo
+ Enretaj navigiloj
+ Dosierujoj
+ Elekti dosierujon
+ Elekti dosierujon aŭ krei novan
+ Malplena
\ No newline at end of file
diff --git a/OsmAnd/res/values-es-rAR/strings.xml b/OsmAnd/res/values-es-rAR/strings.xml
index 2b3d261317..610cf4435a 100644
--- a/OsmAnd/res/values-es-rAR/strings.xml
+++ b/OsmAnd/res/values-es-rAR/strings.xml
@@ -4049,4 +4049,6 @@
Automóvil
Error, vuelve a comprobar los parámetros
Copiar dirección
+ Motor de navegación en línea
+ Motores de navegación en línea
\ No newline at end of file
diff --git a/OsmAnd/res/values-fr/phrases.xml b/OsmAnd/res/values-fr/phrases.xml
index 83c34749e1..e2b1ca9638 100644
--- a/OsmAnd/res/values-fr/phrases.xml
+++ b/OsmAnd/res/values-fr/phrases.xml
@@ -512,7 +512,7 @@
Football canadien
Cyclisme
Tir
- Psychothérapeute
+ Kinésithérapeute
Ergothérapeute
Ferme
Jardins familiaux
diff --git a/OsmAnd/res/values-fr/strings.xml b/OsmAnd/res/values-fr/strings.xml
index 008a82ffa3..ed159ba3d4 100644
--- a/OsmAnd/res/values-fr/strings.xml
+++ b/OsmAnd/res/values-fr/strings.xml
@@ -4023,4 +4023,10 @@
Modifier le moteur de routage en ligne
L\'URL avec tous les paramètres sera de la forme :
Copier l\'adresse
+ Moteur de routage en ligne
+ Moteurs de routage en ligne
+ Dossiers
+ Sélectionnez le dossier
+ Sélectionnez un dossier ou créez-en un nouveau
+ Vide
\ No newline at end of file
diff --git a/OsmAnd/res/values-gl/strings.xml b/OsmAnd/res/values-gl/strings.xml
index f096f64d68..2b37db8ab3 100644
--- a/OsmAnd/res/values-gl/strings.xml
+++ b/OsmAnd/res/values-gl/strings.xml
@@ -3958,7 +3958,7 @@ Lon %2$s
MGRS
MGRS
O OsmAnd emprega MGRS, que é semellante ó formato UTM NATO.
- %1$s datos dispoñíbeis só nas estrada, necesitas calcular unha ruta empregando \"Ruta entre puntos\" para obtela.
+ Os datos de %1$s só dispoñíbeis nas estradas, calcula unha ruta empregando \"Ruta entre puntos\" para ver gráficas.
O gráfico estará dispoñíbel após o recálculo da ruta.
Mapas locais
Salto
@@ -4050,4 +4050,27 @@ Lon %2$s
Permitir regatos e cunetas
Permitir canles de auga intermitentes
Permitir canles de auga intermitentes
+ Engadir motor de navegación en liña
+ Editar motor de navegación en liña
+ Subtipo
+ Vehículo
+ Chave da API
+ URL do servidor
+ Insire parámetro
+ Mantenlo baleiro se non
+ A URL con todos os parámetros será así:
+ Cálculo da ruta de proba
+ Conducindo
+ Pé
+ Bicicleta
+ Coche
+ Erro, verifica novamente os parámetros
+ Copiar enderezo
+ Horarios dos avisos por voz
+ Motor de navegación en liña
+ Motores de navegación en liña
+ Cartafoles
+ Selecionar cartafol ou engadir un novo
+ Seleccionar cartafol
+ Baleiro
\ No newline at end of file
diff --git a/OsmAnd/res/values-hu/strings.xml b/OsmAnd/res/values-hu/strings.xml
index f411c3da1b..4aa49b1705 100644
--- a/OsmAnd/res/values-hu/strings.xml
+++ b/OsmAnd/res/values-hu/strings.xml
@@ -4036,4 +4036,10 @@
Útvonaltervezés kipróbálása
Hiba, ellenőrizze újra a paramétereket
Cím másolása
+ Online útvonaltervező
+ Online útvonaltervezők
+ Mappák
+ Mappa kijelölése
+ Mappa kijelölése vagy új hozzáadása
+ Üres
\ No newline at end of file
diff --git a/OsmAnd/res/values-is/phrases.xml b/OsmAnd/res/values-is/phrases.xml
index fb51911ead..76fbd92412 100644
--- a/OsmAnd/res/values-is/phrases.xml
+++ b/OsmAnd/res/values-is/phrases.xml
@@ -286,7 +286,7 @@
Lífgas
Fljótandi vetni
Rafmagn
- Hleðslustöð
+ Hleðslustöð;Hleðslustöð fyrir rafknúin farartæki;EV-hleðslustöð;Hleðslustæði;Rafhleðslustæði;Þjónustustöð fyrir rafknúin farartæki
Loftdæla
Mótorhjólastæði
Aðgangur að bílastæði
@@ -3883,4 +3883,8 @@
Þvottaþró (þvottaaðstaða)
Á
Bækistöð öryggisvarða
+ Göng fyrir leðurblökur
+ Brú fyrir leðurblökur
+ Þverun villtra dýra
+ Sundsvæði
\ No newline at end of file
diff --git a/OsmAnd/res/values-is/strings.xml b/OsmAnd/res/values-is/strings.xml
index a5e5e86d40..62bafea541 100644
--- a/OsmAnd/res/values-is/strings.xml
+++ b/OsmAnd/res/values-is/strings.xml
@@ -4029,4 +4029,29 @@
Notandasnið
Snúa við öllum punktum
OsmAnd-snið
+ Tímasetning raddskipana
+ Veldu sniðið sem verður notað þegar forritið er ræst.
+ Síðast notað
+ Velja frekar gönguleiðir
+ Velja frekar gönguleiðir
+ Leyfa læki og afföll
+ Leyfa læki og afföll
+ Leyfa tímabundnar vatnaleiðir
+ Leyfa tímabundnar vatnaleiðir
+ Bæta við leiðagerð af netinu
+ Breyta nettengdri leiðagerð
+ Undirtegund
+ Farartæki
+ API-lykill
+ Vefslóð netþjóns
+ Setja inn breytu
+ Halda þessu auðu ef ekki
+ Vefslóð með öllum breytum mun líta svona út:
+ Útreikningur prufuleiðar
+ Akstur
+ Gangandi
+ Hjólandi
+ Bíll
+ Villa, yfirfarðu breytur
+ Afrita heimilisfang
\ No newline at end of file
diff --git a/OsmAnd/res/values-iw/strings.xml b/OsmAnd/res/values-iw/strings.xml
index fa7a3545a9..905fadb16d 100644
--- a/OsmAnd/res/values-iw/strings.xml
+++ b/OsmAnd/res/values-iw/strings.xml
@@ -4048,4 +4048,10 @@
מכונית
שגיאה, נא לבדוק את המשתנים מחדש
העתקת כתובת
+ מנוע ניווט מקוון
+ מנועי ניווט מקוונים
+ תיקיות
+ בחירת תקינה
+ נא לבחור תיקייה או להוסיף אחת חדשה
+ ריק
\ No newline at end of file
diff --git a/OsmAnd/res/values-nl/strings.xml b/OsmAnd/res/values-nl/strings.xml
index b9061fecbf..4313500cc9 100644
--- a/OsmAnd/res/values-nl/strings.xml
+++ b/OsmAnd/res/values-nl/strings.xml
@@ -3940,4 +3940,30 @@
Beken en sloten gebruiken
Beken en sloten gebruiken
Waterwegen die periodiek water voeren gebruiken
+ Selecteer een map
+ Selecteer een map of maak een nieuwe
+ Leeg
+ Selecteer de groepen om deze te importeren.
+ Selecteer de items om deze te importeren.
+ Voeg toe aan Mapillary
+ Voeg toe aan OpenPlaceReviews
+ Gebruik dev.openstreetmap.org
+ Selecteer het profiel dat zal worden gebruikt bij het starten van de applicatie.
+ Online routeplanner toevoegen
+ Bewerk online routeplanner
+ Subtype
+ Voertuig
+ API-sleutel
+ Server-URL
+ De URL met alle parameters ziet er als volgt uit:
+ Test routeberekening
+ Rijden
+ Te voet
+ Fiets
+ Auto
+ Fout, controleer parameters opnieuw
+ Kopieer adres
+ Online routeplanningssysteem
+ Online routeplanningssystemen
+ Mappen
\ No newline at end of file
diff --git a/OsmAnd/res/values-pt-rBR/strings.xml b/OsmAnd/res/values-pt-rBR/strings.xml
index 8516bae334..5348b7283d 100644
--- a/OsmAnd/res/values-pt-rBR/strings.xml
+++ b/OsmAnd/res/values-pt-rBR/strings.xml
@@ -4038,4 +4038,11 @@
Bicicleta
Carro
Erro, verifique novamente os parâmetros
+ Copiar endereço
+ Motor de encaminhamento online
+ Mecanismos de roteamento online
+ Pastas
+ Selecione a pasta
+ Selecione a pasta ou adicione uma nova
+ Vazio
\ No newline at end of file
diff --git a/OsmAnd/res/values-pt/phrases.xml b/OsmAnd/res/values-pt/phrases.xml
index a1ee9f3b00..9b7cae20de 100644
--- a/OsmAnd/res/values-pt/phrases.xml
+++ b/OsmAnd/res/values-pt/phrases.xml
@@ -3879,4 +3879,7 @@
Torneira
Estação de tratamento de água
Posto de guarda florestal
+ Túnel de morcegos
+ Ponte de morcegos
+ Área de natação
\ No newline at end of file
diff --git a/OsmAnd/res/values-ru/strings.xml b/OsmAnd/res/values-ru/strings.xml
index 59bc5514c9..4af14aab63 100644
--- a/OsmAnd/res/values-ru/strings.xml
+++ b/OsmAnd/res/values-ru/strings.xml
@@ -4005,4 +4005,14 @@
Последний раз использовалось
Разрешить прерывистые водные пути
Разрешить прерывистые водные пути
+ • Добавлена возможность экспорта и импорта всех данных, включая настройки, ресурсы, мои места.
+\n
+\n• Планирование маршрута: графики для сегментов трека с маршрутом, добавлена возможность создавать и редактировать несколько сегментов трека.
+\n
+\n• Добавлен OAuth метод аутентификации для OpenStreetMap, улучшен интерфейс диалоговых OSM.
+\n
+\n • Поддержка пользовательских цветов для избранного и путевых точек трека.
+\n
+\n
+ Скопировать адрес
\ No newline at end of file
diff --git a/OsmAnd/res/values-sc/strings.xml b/OsmAnd/res/values-sc/strings.xml
index 4dea386d11..7982e1a5c7 100644
--- a/OsmAnd/res/values-sc/strings.xml
+++ b/OsmAnd/res/values-sc/strings.xml
@@ -4025,4 +4025,26 @@
Permite caminos de abba intermitentes
Permite caminos de abba intermitentes
Nùmeru de annùntzios vocales
+ Annanghe unu motore de càrculu de s\'àndala in lìnia
+ Modìfica su motore de càrculu de s\'àndala in lìnia
+ Suta-casta
+ Veìculu
+ Crae de s\'API
+ URL de su serbidore
+ Inserta su paràmetru
+ Si nono, mantene·lu bòidu
+ S\'URL cun totu sos paràmetros at a apàrrere gasi:
+ Proa a carculare un\'àndala
+ In vetura
+ A pee
+ Bitzicleta
+ Màchina
+ Errore, torra a verificare sos paràmetros
+ Còpia s\'indiritzu
+ Motore de càrculu in lìnia
+ Motores de càrculu in lìnia
+ Cartellas
+ Ischerta sa cartella
+ Ischerta una cartella o crea·nde una noa
+ Bòidu
\ No newline at end of file
diff --git a/OsmAnd/res/values-sk/strings.xml b/OsmAnd/res/values-sk/strings.xml
index 3af8231c15..56a700b27b 100644
--- a/OsmAnd/res/values-sk/strings.xml
+++ b/OsmAnd/res/values-sk/strings.xml
@@ -4043,4 +4043,7 @@
Bicykel
Auto
Chyba, skontrolujte parametre
+ Kopírovať adresu
+ Online navigačná služba
+ Online navigačné služby
\ No newline at end of file
diff --git a/OsmAnd/res/values-tr/strings.xml b/OsmAnd/res/values-tr/strings.xml
index 2e1ed5e651..3633266c59 100644
--- a/OsmAnd/res/values-tr/strings.xml
+++ b/OsmAnd/res/values-tr/strings.xml
@@ -3999,4 +3999,10 @@
Araba
Hata, parametreleri tekrar gözden geçirin
Adresi kopyala
+ Çevrim içi yönlendirme motoru
+ Çevrim içi yönlendirme motorları
+ Klasörler
+ Klasör seç
+ Klasör seçin veya yeni bir tane ekleyin
+ Boş
\ No newline at end of file
diff --git a/OsmAnd/res/values-uk/strings.xml b/OsmAnd/res/values-uk/strings.xml
index dfe36591a5..a78f27f55d 100644
--- a/OsmAnd/res/values-uk/strings.xml
+++ b/OsmAnd/res/values-uk/strings.xml
@@ -4039,4 +4039,11 @@
Велосипед
Автомобіль
Помилка, повторно перевірте параметри
+ Копіювати адресу
+ Мережний рушій маршрутизації
+ Мережні рушії маршрутизації
+ Теки
+ Вибрати теку
+ Виберіть теку або додайте нову
+ Порожньо
\ No newline at end of file
diff --git a/OsmAnd/res/values-zh-rTW/strings.xml b/OsmAnd/res/values-zh-rTW/strings.xml
index 9e432f64ed..74513f74f7 100644
--- a/OsmAnd/res/values-zh-rTW/strings.xml
+++ b/OsmAnd/res/values-zh-rTW/strings.xml
@@ -4039,4 +4039,10 @@
汽車
錯誤,重新檢查參數
複製地址
+ 線上路線計算引擎
+ 線上路線計算引擎
+ 資料夾
+ 選取資料夾
+ 選取資料夾或新增
+ 空
\ No newline at end of file
diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml
index 47645eb555..e390145312 100644
--- a/OsmAnd/res/values/strings.xml
+++ b/OsmAnd/res/values/strings.xml
@@ -7,11 +7,15 @@
1. To not produce duplicate strings (check by name if a string already exists)
2. Every apostrophe (quote) is preceded by a backslash.
3. If you modify the English strings file, please add new strings at the top of the file, this makes periodic reviews before releases easier.
- - For wording and consistency, please note https://osmand.net/help-online?id=technical-articles#Creating_a_Consistent_User_Experience
+ - For wording and consistency, please note https://docs.osmand.net/en/main@latest/development/contributing-to-osmand/translating-osmand
Thx - Hardy
-->
+ Empty
+ Select folder or add new one
+ Select folder
+ Folders
Online routing engines
Online routing engine
Copy address
diff --git a/OsmAnd/src/net/osmand/FileUtils.java b/OsmAnd/src/net/osmand/FileUtils.java
index 1f9a755be5..fed5346212 100644
--- a/OsmAnd/src/net/osmand/FileUtils.java
+++ b/OsmAnd/src/net/osmand/FileUtils.java
@@ -1,27 +1,24 @@
package net.osmand;
-import android.app.Activity;
-import android.content.DialogInterface;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.view.View;
-import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+import net.osmand.GPXUtilities.GPXFile;
+import net.osmand.GPXUtilities.Metadata;
import net.osmand.plus.GpxSelectionHelper;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
-import net.osmand.plus.SQLiteTileSource;
+import net.osmand.plus.dialogs.RenameFileBottomSheet;
import net.osmand.util.Algorithms;
import java.io.File;
import java.io.IOException;
-import java.lang.ref.WeakReference;
import java.util.regex.Pattern;
public class FileUtils {
@@ -29,70 +26,11 @@ public class FileUtils {
public static final Pattern ILLEGAL_FILE_NAME_CHARACTERS = Pattern.compile("[?:\"*|/<>]");
public static final Pattern ILLEGAL_PATH_NAME_CHARACTERS = Pattern.compile("[?:\"*|<>]");
- public static void renameFile(Activity a, final File f, final RenameCallback callback) {
- final WeakReference weakActivity = new WeakReference<>(a);
- AlertDialog.Builder b = new AlertDialog.Builder(a);
- if (f.exists()) {
- int xt = f.getName().lastIndexOf('.');
- final String ext = xt == -1 ? "" : f.getName().substring(xt);
- final String originalName = xt == -1 ? f.getName() : f.getName().substring(0, xt);
- final EditText editText = new EditText(a);
- editText.setText(originalName);
- editText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- Editable text = editText.getText();
- if (text.length() >= 1) {
- Activity activity = weakActivity.get();
- if (ILLEGAL_FILE_NAME_CHARACTERS.matcher(text).find() && activity != null) {
- editText.setError(activity.getString(R.string.file_name_containes_illegal_char));
- }
- }
- }
- });
- b.setTitle(R.string.shared_string_rename);
- int leftPadding = AndroidUtils.dpToPx(a, 24f);
- int topPadding = AndroidUtils.dpToPx(a, 4f);
- b.setView(editText, leftPadding, topPadding, leftPadding, topPadding);
- // Behaviour will be overwritten later;
- b.setPositiveButton(R.string.shared_string_save, null);
- b.setNegativeButton(R.string.shared_string_cancel, null);
- final AlertDialog alertDialog = b.create();
- alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
- @Override
- public void onShow(DialogInterface dialog) {
- alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Activity activity = weakActivity.get();
- if (activity != null) {
- OsmandApplication app = (OsmandApplication) activity.getApplication();
- if (ext.equals(SQLiteTileSource.EXT)) {
- if (renameSQLiteFile(app, f, editText.getText().toString() + ext,
- callback) != null) {
- alertDialog.dismiss();
- }
- } else {
- if (renameGpxFile(app, f, editText.getText().toString() + ext,
- false, callback) != null) {
- alertDialog.dismiss();
- }
- }
- }
- }
- });
- }
- });
- alertDialog.show();
+ public static void renameFile(@NonNull FragmentActivity activity, @NonNull File file,
+ @Nullable Fragment target, boolean usedOnMap) {
+ if (file.exists()) {
+ FragmentManager fragmentManager = activity.getSupportFragmentManager();
+ RenameFileBottomSheet.showInstance(fragmentManager, target, file, usedOnMap);
}
}
@@ -106,7 +44,7 @@ public class FileUtils {
dest.getParentFile().mkdirs();
}
if (source.renameTo(dest)) {
- final String[] suffixes = new String[]{"-journal", "-wal", "-shm"};
+ final String[] suffixes = new String[] {"-journal", "-wal", "-shm"};
for (String s : suffixes) {
File file = new File(ctx.getDatabasePath(source + s).toString());
if (file.exists()) {
@@ -140,6 +78,26 @@ public class FileUtils {
return res;
}
+ public static File renameFile(@NonNull OsmandApplication app, @NonNull File source,
+ @NonNull String newName, boolean dirAllowed, RenameCallback callback) {
+ File dest = checkRenamePossibility(app, source, newName, dirAllowed);
+ if (dest == null) {
+ return null;
+ }
+ if (!dest.getParentFile().exists()) {
+ dest.getParentFile().mkdirs();
+ }
+ File res = source.renameTo(dest) ? dest : null;
+ if (res != null) {
+ if (callback != null) {
+ callback.renamedTo(res);
+ }
+ } else {
+ Toast.makeText(app, R.string.file_can_not_be_renamed, Toast.LENGTH_LONG).show();
+ }
+ return res;
+ }
+
public static File renameGpxFile(@NonNull OsmandApplication app, @NonNull File src, @NonNull File dest) {
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();
diff --git a/OsmAnd/src/net/osmand/plus/activities/HelpActivity.java b/OsmAnd/src/net/osmand/plus/activities/HelpActivity.java
index 84e491971b..8be1564068 100644
--- a/OsmAnd/src/net/osmand/plus/activities/HelpActivity.java
+++ b/OsmAnd/src/net/osmand/plus/activities/HelpActivity.java
@@ -168,8 +168,6 @@ public class HelpActivity extends OsmandActionBarActivity implements AdapterView
contextMenuAdapter.addItem(createCategory(R.string.other_menu_group));
contextMenuAdapter.addItem(createItem(R.string.instalation_troubleshooting_item, NULL_ID,
"feature_articles/installation-and-troubleshooting.html"));
- contextMenuAdapter.addItem(createItem(R.string.techical_articles_item, NULL_ID,
- "feature_articles/technical-articles.html"));
contextMenuAdapter.addItem(createItem(R.string.versions_item, NULL_ID,
"feature_articles/changes.html"));
contextMenuAdapter.addItem(createItem(R.string.what_is_new, NULL_ID,
diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java
index 3ed8053ca4..c526ddec2a 100644
--- a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java
+++ b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java
@@ -63,8 +63,8 @@ import net.osmand.plus.measurementtool.MeasurementToolFragment;
import net.osmand.plus.measurementtool.StartPlanRouteBottomSheet;
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
import net.osmand.plus.osmedit.dialogs.DismissRouteBottomSheetFragment;
+import net.osmand.plus.profiles.ProfileDataObject;
import net.osmand.plus.profiles.ProfileDataUtils;
-import net.osmand.plus.profiles.RoutingProfileDataObject;
import net.osmand.plus.routepreparationmenu.MapRouteInfoMenu;
import net.osmand.plus.routepreparationmenu.WaypointsFragment;
import net.osmand.plus.routing.RouteProvider.GPXRouteParamsBuilder;
@@ -737,7 +737,7 @@ public class MapActivityActions implements DialogProvider {
String modeDescription;
- Map profilesObjects = ProfileDataUtils.getRoutingProfiles(app);
+ Map profilesObjects = ProfileDataUtils.getRoutingProfiles(app);
for (final ApplicationMode appMode : activeModes) {
if (appMode.isCustomProfile()) {
modeDescription = getProfileDescription(app, appMode, profilesObjects, getString(R.string.profile_type_user_string));
@@ -1046,7 +1046,7 @@ public class MapActivityActions implements DialogProvider {
//switch profile button
ApplicationMode currentMode = app.getSettings().APPLICATION_MODE.get();
String modeDescription;
- Map profilesObjects = ProfileDataUtils.getRoutingProfiles(app);
+ Map profilesObjects = ProfileDataUtils.getRoutingProfiles(app);
if (currentMode.isCustomProfile()) {
modeDescription = getProfileDescription(app, currentMode, profilesObjects, getString(R.string.profile_type_user_string));
} else {
@@ -1087,12 +1087,12 @@ public class MapActivityActions implements DialogProvider {
}
private String getProfileDescription(OsmandApplication app, ApplicationMode mode,
- Map profilesObjects, String defaultDescription) {
+ Map profilesObjects, String defaultDescription) {
String description = defaultDescription;
String routingProfileKey = mode.getRoutingProfile();
if (!Algorithms.isEmpty(routingProfileKey)) {
- RoutingProfileDataObject profileDataObject = profilesObjects.get(routingProfileKey);
+ ProfileDataObject profileDataObject = profilesObjects.get(routingProfileKey);
if (profileDataObject != null) {
description = String.format(app.getString(R.string.profile_type_descr_string),
Algorithms.capitalizeFirstLetterAndLowercase(profileDataObject.getName()));
diff --git a/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java b/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java
index 839823c369..e249fc2770 100644
--- a/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java
+++ b/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java
@@ -5,6 +5,7 @@ import android.content.Intent;
import android.content.res.ColorStateList;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.PersistableBundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MenuItem;
@@ -45,6 +46,7 @@ import net.osmand.plus.settings.backend.OsmAndAppCustomization;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.track.TrackDisplayHelper;
import net.osmand.plus.views.AddGpxPointBottomSheetHelper.NewGpxPoint;
+import net.osmand.util.Algorithms;
import java.io.File;
import java.lang.ref.WeakReference;
@@ -83,10 +85,35 @@ public class TrackActivity extends TabActivity {
return;
}
displayHelper = new TrackDisplayHelper(app);
- if (intent.hasExtra(TRACK_FILE_NAME)) {
+ if (savedInstanceState != null) {
+ String path = savedInstanceState.getString(TRACK_FILE_NAME);
+ if (!Algorithms.isEmpty(path)) {
+ displayHelper.setFile(new File(path));
+ }
+ } else if (intent.hasExtra(TRACK_FILE_NAME)) {
displayHelper.setFile(new File(intent.getStringExtra(TRACK_FILE_NAME)));
}
+ setupActionBar();
+ if (intent.hasExtra(OPEN_POINTS_TAB)
+ || (savedInstanceState != null && savedInstanceState.getBoolean(OPEN_POINTS_TAB, false))) {
+ openPointsTab = true;
+ }
+ if (intent.hasExtra(OPEN_TRACKS_LIST)) {
+ openTracksList = true;
+ }
+ setContentView(R.layout.track_content);
+ }
+
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) {
+ File file = getFile();
+ outState.putString(TRACK_FILE_NAME, file != null ? file.getAbsolutePath() : null);
+ outState.putBoolean(CURRENT_RECORDING, file == null);
+ super.onSaveInstanceState(outState, outPersistentState);
+ }
+
+ public void setupActionBar() {
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
if (getFile() != null) {
@@ -97,14 +124,6 @@ public class TrackActivity extends TabActivity {
}
actionBar.setElevation(AndroidUtils.dpToPx(app, 4f));
}
- if (intent.hasExtra(OPEN_POINTS_TAB)
- || (savedInstanceState != null && savedInstanceState.getBoolean(OPEN_POINTS_TAB, false))) {
- openPointsTab = true;
- }
- if (intent.hasExtra(OPEN_TRACKS_LIST)) {
- openTracksList = true;
- }
- setContentView(R.layout.track_content);
}
public TrackDisplayHelper getDisplayHelper() {
diff --git a/OsmAnd/src/net/osmand/plus/dialogs/RenameFileBottomSheet.java b/OsmAnd/src/net/osmand/plus/dialogs/RenameFileBottomSheet.java
new file mode 100644
index 0000000000..c6057b56de
--- /dev/null
+++ b/OsmAnd/src/net/osmand/plus/dialogs/RenameFileBottomSheet.java
@@ -0,0 +1,168 @@
+package net.osmand.plus.dialogs;
+
+import android.content.res.ColorStateList;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+
+import com.google.android.material.textfield.TextInputEditText;
+import com.google.android.material.textfield.TextInputLayout;
+
+import net.osmand.AndroidUtils;
+import net.osmand.FileUtils.RenameCallback;
+import net.osmand.IndexConstants;
+import net.osmand.PlatformUtil;
+import net.osmand.plus.OsmandApplication;
+import net.osmand.plus.R;
+import net.osmand.plus.SQLiteTileSource;
+import net.osmand.plus.UiUtilities;
+import net.osmand.plus.base.MenuBottomSheetDialogFragment;
+import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
+import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
+import net.osmand.util.Algorithms;
+
+import org.apache.commons.logging.Log;
+
+import java.io.File;
+
+import static net.osmand.FileUtils.ILLEGAL_FILE_NAME_CHARACTERS;
+import static net.osmand.FileUtils.renameFile;
+import static net.osmand.FileUtils.renameGpxFile;
+import static net.osmand.FileUtils.renameSQLiteFile;
+
+public class RenameFileBottomSheet extends MenuBottomSheetDialogFragment {
+
+ private static final Log LOG = PlatformUtil.getLog(RenameFileBottomSheet.class);
+ private static final String TAG = RenameFileBottomSheet.class.getName();
+ private static final String SOURCE_FILE_NAME_KEY = "source_file_name_key";
+ private static final String SELECTED_FILE_NAME_KEY = "selected_file_name_key";
+
+ private OsmandApplication app;
+
+ private TextInputEditText editText;
+ private TextInputLayout nameTextBox;
+
+ private File file;
+ private String selectedFileName;
+
+ @Override
+ public void createMenuItems(Bundle savedInstanceState) {
+ app = requiredMyApplication();
+ if (savedInstanceState != null) {
+ String path = savedInstanceState.getString(SOURCE_FILE_NAME_KEY);
+ if (!Algorithms.isEmpty(path)) {
+ file = new File(path);
+ }
+ selectedFileName = savedInstanceState.getString(SELECTED_FILE_NAME_KEY);
+ }
+ items.add(new TitleItem(getString(R.string.shared_string_rename)));
+
+ View view = UiUtilities.getInflater(app, nightMode).inflate(R.layout.track_name_edit_text, null);
+ nameTextBox = view.findViewById(R.id.name_text_box);
+ nameTextBox.setBoxBackgroundColorResource(nightMode ? R.color.list_background_color_dark : R.color.activity_background_color_light);
+ nameTextBox.setHint(AndroidUtils.addColon(app, R.string.shared_string_name));
+ ColorStateList colorStateList = ColorStateList.valueOf(ContextCompat
+ .getColor(app, nightMode ? R.color.text_color_secondary_dark : R.color.text_color_secondary_light));
+ nameTextBox.setDefaultHintTextColor(colorStateList);
+
+ editText = view.findViewById(R.id.name_edit_text);
+ editText.setText(selectedFileName != null ? selectedFileName : Algorithms.getFileNameWithoutExtension(file));
+ editText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ updateFileName(s.toString());
+ }
+ });
+
+ BaseBottomSheetItem editFolderName = new BaseBottomSheetItem.Builder()
+ .setCustomView(view)
+ .create();
+ items.add(editFolderName);
+ }
+
+ private void updateFileName(String name) {
+ if (!Algorithms.isEmpty(name) && ILLEGAL_FILE_NAME_CHARACTERS.matcher(name).find()) {
+ nameTextBox.setError(getString(R.string.file_name_containes_illegal_char));
+ } else {
+ selectedFileName = name;
+ nameTextBox.setError(null);
+ }
+ updateBottomButtons();
+ }
+
+ @Override
+ protected boolean isRightBottomButtonEnabled() {
+ return nameTextBox.getError() == null;
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ outState.putString(SOURCE_FILE_NAME_KEY, file.getAbsolutePath());
+ outState.putString(SELECTED_FILE_NAME_KEY, selectedFileName);
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onRightBottomButtonClick() {
+ FragmentActivity activity = getActivity();
+ if (activity != null) {
+ AndroidUtils.hideSoftKeyboard(activity, editText);
+ }
+ File dest;
+ int index = file.getName().lastIndexOf('.');
+ String ext = index == -1 ? "" : file.getName().substring(index);
+ if (SQLiteTileSource.EXT.equals(ext)) {
+ dest = renameSQLiteFile(app, file, selectedFileName + ext, null);
+ } else if (IndexConstants.GPX_FILE_EXT.equals(ext)) {
+ dest = renameGpxFile(app, file, selectedFileName + ext, false, null);
+ } else {
+ dest = renameFile(app, file, selectedFileName + ext, false, null);
+ }
+ if (dest != null) {
+ Fragment fragment = getTargetFragment();
+ if (fragment instanceof RenameCallback) {
+ RenameCallback listener = (RenameCallback) fragment;
+ listener.renamedTo(dest);
+ }
+ dismiss();
+ }
+ }
+
+ @Override
+ protected int getDismissButtonTextId() {
+ return R.string.shared_string_cancel;
+ }
+
+ @Override
+ protected int getRightBottomButtonTextId() {
+ return R.string.shared_string_save;
+ }
+
+ public static void showInstance(@NonNull FragmentManager fragmentManager, @Nullable Fragment target,
+ @NonNull File file, boolean usedOnMap) {
+ if (file.exists() && !fragmentManager.isStateSaved()
+ && fragmentManager.findFragmentByTag(RenameFileBottomSheet.TAG) == null) {
+ RenameFileBottomSheet fragment = new RenameFileBottomSheet();
+ fragment.file = file;
+ fragment.setUsedOnMap(usedOnMap);
+ fragment.setTargetFragment(target, 0);
+ fragment.show(fragmentManager, RenameFileBottomSheet.TAG);
+ }
+ }
+}
\ No newline at end of file
diff --git a/OsmAnd/src/net/osmand/plus/download/ui/LocalIndexesFragment.java b/OsmAnd/src/net/osmand/plus/download/ui/LocalIndexesFragment.java
index 9160160973..3081c0680b 100644
--- a/OsmAnd/src/net/osmand/plus/download/ui/LocalIndexesFragment.java
+++ b/OsmAnd/src/net/osmand/plus/download/ui/LocalIndexesFragment.java
@@ -29,6 +29,7 @@ import androidx.appcompat.view.ActionMode;
import androidx.appcompat.widget.PopupMenu;
import androidx.core.content.ContextCompat;
import androidx.core.view.MenuItemCompat;
+import androidx.fragment.app.FragmentActivity;
import net.osmand.AndroidUtils;
import net.osmand.Collator;
@@ -74,7 +75,7 @@ import java.util.Map;
import java.util.Set;
public class LocalIndexesFragment extends OsmandExpandableListFragment implements DownloadEvents,
- OnMapSourceUpdateListener {
+ OnMapSourceUpdateListener, RenameCallback {
private LoadLocalIndexTask asyncLoader;
private Map filesToUpdate = new HashMap<>();
private LocalIndexesAdapter listAdapter;
@@ -141,13 +142,11 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
private boolean performBasicOperation(int resId, final LocalIndexInfo info) {
if (resId == R.string.shared_string_rename) {
- FileUtils.renameFile(getActivity(), new File(info.getPathToData()), new RenameCallback() {
-
- @Override
- public void renamedTo(File file) {
- getDownloadActivity().reloadLocalIndexes();
- }
- });
+ FragmentActivity activity = getActivity();
+ if (activity != null) {
+ File file = new File(info.getPathToData());
+ FileUtils.renameFile(activity, file, this, false);
+ }
} else if (resId == R.string.clear_tile_data) {
AlertDialog.Builder confirm = new AlertDialog.Builder(getActivity());
confirm.setPositiveButton(R.string.shared_string_yes, new DialogInterface.OnClickListener() {
@@ -188,7 +187,19 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
@Override
public void onMapSourceUpdated() {
- getDownloadActivity().reloadLocalIndexes();
+ reloadLocalIndexes();
+ }
+
+ @Override
+ public void renamedTo(File file) {
+ reloadLocalIndexes();
+ }
+
+ private void reloadLocalIndexes() {
+ DownloadActivity activity = getDownloadActivity();
+ if (activity != null) {
+ activity.reloadLocalIndexes();
+ }
}
public class LoadLocalIndexTask extends AsyncTask>
@@ -666,7 +677,7 @@ public class LocalIndexesFragment extends OsmandExpandableListFragment implement
public void localOptionsMenu(final int itemId) {
if (itemId == R.string.shared_string_refresh) {
- getDownloadActivity().reloadLocalIndexes();
+ reloadLocalIndexes();
} else if (itemId == R.string.shared_string_delete) {
openSelectionMode(itemId, R.drawable.ic_action_delete_dark,
new DialogInterface.OnClickListener() {
diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/AmenityMenuBuilder.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/AmenityMenuBuilder.java
index c0db653e3e..0d097eabfb 100644
--- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/AmenityMenuBuilder.java
+++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/AmenityMenuBuilder.java
@@ -93,18 +93,20 @@ public class AmenityMenuBuilder extends MenuBuilder {
protected void buildNearestPoiRow(View view) {
}
- private void buildRow(View view, int iconId, String text, String textPrefix,
+ private void buildRow(View view, int iconId, String text, String textPrefix, String socialMediaUrl,
boolean collapsable, final CollapsableView collapsableView,
int textColor, boolean isWiki, boolean isText, boolean needLinks,
boolean isPhoneNumber, boolean isUrl, boolean matchWidthDivider, int textLinesLimit) {
- buildRow(view, iconId == 0 ? null : getRowIcon(iconId), text, textPrefix, collapsable, collapsableView, textColor,
+ buildRow(view, iconId == 0 ? null : getRowIcon(iconId), text, textPrefix, socialMediaUrl,
+ collapsable, collapsableView, textColor,
isWiki, isText, needLinks, isPhoneNumber, isUrl, matchWidthDivider, textLinesLimit);
}
protected void buildRow(final View view, Drawable icon, final String text, final String textPrefix,
- boolean collapsable, final CollapsableView collapsableView,
- int textColor, boolean isWiki, boolean isText, boolean needLinks,
- boolean isPhoneNumber, boolean isUrl, boolean matchWidthDivider, int textLinesLimit) {
+ final String socialMediaUrl, boolean collapsable,
+ final CollapsableView collapsableView, int textColor, boolean isWiki,
+ boolean isText, boolean needLinks, boolean isPhoneNumber, boolean isUrl,
+ boolean matchWidthDivider, int textLinesLimit) {
if (!isFirstRow()) {
buildRowDivider(view);
@@ -312,8 +314,9 @@ public class AmenityMenuBuilder extends MenuBuilder {
WikipediaArticleWikiLinkFragment.showInstance(mapActivity.getSupportFragmentManager(), text);
}
} else {
+ String uri = socialMediaUrl == null ? text : socialMediaUrl;
Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(text));
+ intent.setData(Uri.parse(uri));
v.getContext().startActivity(intent);
}
}
@@ -366,6 +369,7 @@ public class AmenityMenuBuilder extends MenuBuilder {
continue;
}
+ String socialMediaUrl = null;
String textPrefix = "";
CollapsableView collapsableView = null;
boolean collapsable = false;
@@ -397,6 +401,11 @@ public class AmenityMenuBuilder extends MenuBuilder {
if (vl.startsWith("http://") || vl.startsWith("https://") || vl.startsWith("HTTP://") || vl.startsWith("HTTPS://")) {
isUrl = true;
+ } else {
+ socialMediaUrl = getSocialMediaUrl(key, vl);
+ if (socialMediaUrl != null) {
+ isUrl = true;
+ }
}
if (pType != null && !pType.isText()) {
@@ -557,16 +566,16 @@ public class AmenityMenuBuilder extends MenuBuilder {
AmenityInfoRow row;
if (isDescription) {
row = new AmenityInfoRow(key, R.drawable.ic_action_note_dark, textPrefix,
- vl, collapsable, collapsableView, 0, false, true,
- true, 0, "", false, false, matchWidthDivider, 0);
+ vl, null, collapsable, collapsableView, 0, false,
+ true, true, 0, "", false, false, matchWidthDivider, 0);
} else if (icon != null) {
- row = new AmenityInfoRow(key, icon, textPrefix, vl, collapsable, collapsableView,
- textColor, isWiki, isText, needLinks, poiTypeOrder, poiTypeKeyName,
- isPhoneNumber, isUrl, matchWidthDivider, 0);
+ row = new AmenityInfoRow(key, icon, textPrefix, vl, socialMediaUrl, collapsable,
+ collapsableView, textColor, isWiki, isText, needLinks, poiTypeOrder,
+ poiTypeKeyName, isPhoneNumber, isUrl, matchWidthDivider, 0);
} else {
- row = new AmenityInfoRow(key, iconId, textPrefix, vl, collapsable, collapsableView,
- textColor, isWiki, isText, needLinks, poiTypeOrder, poiTypeKeyName,
- isPhoneNumber, isUrl, matchWidthDivider, 0);
+ row = new AmenityInfoRow(key, iconId, textPrefix, vl, socialMediaUrl, collapsable,
+ collapsableView, textColor, isWiki, isText, needLinks, poiTypeOrder,
+ poiTypeKeyName, isPhoneNumber, isUrl, matchWidthDivider, 0);
}
if (isDescription) {
descriptions.add(row);
@@ -613,8 +622,11 @@ public class AmenityMenuBuilder extends MenuBuilder {
}
boolean cuisineOrDish = categoryName.equals(Amenity.CUISINE) || categoryName.equals(Amenity.DISH);
CollapsableView collapsableView = getPoiTypeCollapsableView(view.getContext(), true, categoryTypes, true, cuisineOrDish ? cuisineRow : null);
- infoRows.add(new AmenityInfoRow(poiAdditionalCategoryName, icon, pType.getPoiAdditionalCategoryTranslation(), sb.toString(), true, collapsableView,
- 0, false, false, false, pType.getOrder(), pType.getKeyName(), false, false, false, 1));
+ infoRows.add(new AmenityInfoRow(poiAdditionalCategoryName, icon,
+ pType.getPoiAdditionalCategoryTranslation(), sb.toString(), null,
+ true, collapsableView, 0, false, false,
+ false, pType.getOrder(), pType.getKeyName(), false,
+ false, false, 1));
}
}
@@ -629,8 +641,10 @@ public class AmenityMenuBuilder extends MenuBuilder {
}
sb.append(pt.getTranslation());
}
- infoRows.add(new AmenityInfoRow(poiCategory.getKeyName(), icon, poiCategory.getTranslation(), sb.toString(), true, collapsableView,
- 0, false, false, false, 40, poiCategory.getKeyName(), false, false, false, 1));
+ infoRows.add(new AmenityInfoRow(poiCategory.getKeyName(), icon,
+ poiCategory.getTranslation(), sb.toString(), null, true,
+ collapsableView, 0, false, false, false, 40,
+ poiCategory.getKeyName(), false, false, false, 1));
}
Collections.sort(infoRows, new Comparator() {
@@ -670,7 +684,8 @@ public class AmenityMenuBuilder extends MenuBuilder {
if (processNearestWiki() && nearestWiki.size() > 0) {
AmenityInfoRow wikiInfo = new AmenityInfoRow(
- "nearest_wiki", R.drawable.ic_plugin_wikipedia, null, app.getString(R.string.wiki_around) + " (" + nearestWiki.size() + ")", true,
+ "nearest_wiki", R.drawable.ic_plugin_wikipedia, null, app.getString(R.string.wiki_around) + " (" + nearestWiki.size() + ")",
+ null, true,
getCollapsableView(view.getContext(), true, nearestWiki),
0, false, false, false, 1000, null, false, false, false, 0);
buildAmenityRow(view, wikiInfo);
@@ -678,7 +693,8 @@ public class AmenityMenuBuilder extends MenuBuilder {
if (processNearestPoi() && nearestPoi.size() > 0) {
AmenityInfoRow poiInfo = new AmenityInfoRow(
- "nearest_poi", AmenityMenuController.getRightIconId(amenity), null, app.getString(R.string.speak_poi) + " (" + nearestPoi.size() + ")", true,
+ "nearest_poi", AmenityMenuController.getRightIconId(amenity), null, app.getString(R.string.speak_poi) + " (" + nearestPoi.size() + ")",
+ null, true,
getCollapsableView(view.getContext(), true, nearestPoi),
0, false, false, false, 1000, null, false, false, false, 0);
buildAmenityRow(view, poiInfo);
@@ -783,12 +799,14 @@ public class AmenityMenuBuilder extends MenuBuilder {
public void buildAmenityRow(View view, AmenityInfoRow info) {
if (info.icon != null) {
- buildRow(view, info.icon, info.text, info.textPrefix, info.collapsable, info.collapsableView,
- info.textColor, info.isWiki, info.isText, info.needLinks, info.isPhoneNumber,
+ buildRow(view, info.icon, info.text, info.textPrefix, info.socialMediaUrl,
+ info.collapsable, info.collapsableView, info.textColor, info.isWiki, info.isText,
+ info.needLinks, info.isPhoneNumber,
info.isUrl, info.matchWidthDivider, info.textLinesLimit);
} else {
- buildRow(view, info.iconId, info.text, info.textPrefix, info.collapsable, info.collapsableView,
- info.textColor, info.isWiki, info.isText, info.needLinks, info.isPhoneNumber,
+ buildRow(view, info.iconId, info.text, info.textPrefix, info.socialMediaUrl,
+ info.collapsable, info.collapsableView, info.textColor, info.isWiki, info.isText,
+ info.needLinks, info.isPhoneNumber,
info.isUrl, info.matchWidthDivider, info.textLinesLimit);
}
}
@@ -892,12 +910,45 @@ public class AmenityMenuBuilder extends MenuBuilder {
return new CollapsableView(view, this, collapsed);
}
+ private String getSocialMediaUrl(String key, String value) {
+ // Remove leading and closing slashes
+ StringBuilder sb = new StringBuilder(value.trim());
+ if (sb.charAt(0) == '/') {
+ sb.deleteCharAt(0);
+ }
+ int lastIdx = sb.length() - 1;
+ if (sb.charAt(lastIdx) == '/') {
+ sb.deleteCharAt(lastIdx);
+ }
+
+ // It cannot be username
+ if (sb.indexOf("/") != -1) {
+ return "https://" + value;
+ }
+
+ Map urls = new HashMap<>(7);
+ urls.put("facebook", "https://facebook.com/%s");
+ urls.put("vk", "https://vk.com/%s");
+ urls.put("instagram", "https://instagram.com/%s");
+ urls.put("twitter", "https://twitter.com/%s");
+ urls.put("ok", "https://ok.ru/%s");
+ urls.put("telegram", "https://t.me/%s");
+ urls.put("flickr", "https://flickr.com/%s");
+
+ if (urls.containsKey(key)) {
+ return String.format(urls.get(key), value);
+ } else {
+ return null;
+ }
+ }
+
private static class AmenityInfoRow {
private String key;
private Drawable icon;
private int iconId;
private String textPrefix;
private String text;
+ private String socialMediaUrl;
private CollapsableView collapsableView;
private boolean collapsable;
private int textColor;
@@ -912,14 +963,16 @@ public class AmenityMenuBuilder extends MenuBuilder {
private int textLinesLimit;
public AmenityInfoRow(String key, Drawable icon, String textPrefix, String text,
- boolean collapsable, CollapsableView collapsableView,
- int textColor, boolean isWiki, boolean isText, boolean needLinks,
- int order, String name, boolean isPhoneNumber, boolean isUrl,
+ String socialMediaUrl, boolean collapsable,
+ CollapsableView collapsableView, int textColor, boolean isWiki,
+ boolean isText, boolean needLinks, int order, String name,
+ boolean isPhoneNumber, boolean isUrl,
boolean matchWidthDivider, int textLinesLimit) {
this.key = key;
this.icon = icon;
this.textPrefix = textPrefix;
this.text = text;
+ this.socialMediaUrl = socialMediaUrl;
this.collapsable = collapsable;
this.collapsableView = collapsableView;
this.textColor = textColor;
@@ -935,14 +988,16 @@ public class AmenityMenuBuilder extends MenuBuilder {
}
public AmenityInfoRow(String key, int iconId, String textPrefix, String text,
- boolean collapsable, CollapsableView collapsableView,
- int textColor, boolean isWiki, boolean isText, boolean needLinks,
- int order, String name, boolean isPhoneNumber, boolean isUrl,
+ String socialMediaUrl, boolean collapsable,
+ CollapsableView collapsableView, int textColor, boolean isWiki,
+ boolean isText, boolean needLinks, int order, String name,
+ boolean isPhoneNumber, boolean isUrl,
boolean matchWidthDivider, int textLinesLimit) {
this.key = key;
this.iconId = iconId;
this.textPrefix = textPrefix;
this.text = text;
+ this.socialMediaUrl = socialMediaUrl;
this.collapsable = collapsable;
this.collapsableView = collapsableView;
this.textColor = textColor;
diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/SaveAsNewTrackBottomSheetDialogFragment.java b/OsmAnd/src/net/osmand/plus/measurementtool/SaveAsNewTrackBottomSheetDialogFragment.java
index 5b4058f339..90cbd1446e 100644
--- a/OsmAnd/src/net/osmand/plus/measurementtool/SaveAsNewTrackBottomSheetDialogFragment.java
+++ b/OsmAnd/src/net/osmand/plus/measurementtool/SaveAsNewTrackBottomSheetDialogFragment.java
@@ -8,6 +8,7 @@ import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
+import android.view.View.OnClickListener;
import android.widget.EditText;
import android.widget.Toast;
@@ -16,13 +17,16 @@ import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
+import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.textfield.TextInputEditText;
import com.google.android.material.textfield.TextInputLayout;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities;
+import net.osmand.GPXUtilities.GPXFile;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
@@ -35,12 +39,17 @@ import net.osmand.plus.base.bottomsheetmenu.HorizontalRecyclerBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerSpaceItem;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
import net.osmand.plus.measurementtool.adapter.FolderListAdapter;
+import net.osmand.plus.myplaces.MoveGpxFileBottomSheet;
+import net.osmand.plus.myplaces.MoveGpxFileBottomSheet.OnTrackFileMoveListener;
+import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
-public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDialogFragment {
+public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDialogFragment implements OnTrackFileMoveListener {
public static final String TAG = SaveAsNewTrackBottomSheetDialogFragment.class.getSimpleName();
private static final Log LOG = PlatformUtil.getLog(SaveAsNewTrackBottomSheetDialogFragment.class);
@@ -52,19 +61,24 @@ public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDial
public static final String SOURCE_FOLDER_NAME_KEY = "source_folder_name_key";
public static final String SHOW_SIMPLIFIED_BUTTON_KEY = "show_simplified_button_key";
- private boolean showOnMap;
- private boolean simplifiedTrack;
+ private OsmandApplication app;
+
+ private FolderListAdapter adapter;
+ private TextInputLayout nameTextBox;
+ private RecyclerView recyclerView;
+
private String fileName;
private String sourceFileName;
private String sourceFolderName;
private String folderName;
+ private boolean showOnMap;
+ private boolean simplifiedTrack;
private boolean rightButtonEnabled = true;
private boolean showSimplifiedButton = true;
- private TextInputLayout nameTextBox;
@Override
public void createMenuItems(Bundle savedInstanceState) {
- OsmandApplication app = getMyApplication();
+ app = getMyApplication();
if (app == null) {
return;
}
@@ -118,12 +132,30 @@ public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDial
items.add(new DividerSpaceItem(app, contentPaddingSmall));
- FolderListAdapter adapter = new FolderListAdapter(app, nightMode, folderName);
+ View selectFolderView = View.inflate(UiUtilities.getThemedContext(app, nightMode), R.layout.select_folder_row, null);
+ selectFolderView.findViewById(R.id.select_folder_button).setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FragmentActivity activity = getActivity();
+ if (activity != null) {
+ File dest = getFile(app, folderName, fileName);
+ MoveGpxFileBottomSheet.showInstance(activity.getSupportFragmentManager(),
+ SaveAsNewTrackBottomSheetDialogFragment.this, dest.getAbsolutePath(), usedOnMap);
+ }
+ }
+ });
+ BaseBottomSheetItem selectFolderItem = new BaseBottomSheetItem.Builder()
+ .setCustomView(selectFolderView)
+ .create();
+ items.add(selectFolderItem);
+
+ adapter = new FolderListAdapter(app, nightMode, folderName);
+ adapter.setFolders(getFolders());
if (adapter.getItemCount() > 0) {
adapter.setListener(createFolderSelectListener());
View view = View.inflate(UiUtilities.getThemedContext(app, nightMode), R.layout.bottom_sheet_item_recyclerview,
null);
- View recyclerView = view.findViewById(R.id.recycler_view);
+ recyclerView = view.findViewById(R.id.recycler_view);
recyclerView.setPadding(contentPaddingHalf, 0, contentPaddingHalf, 0);
BaseBottomSheetItem scrollItem = new HorizontalRecyclerBottomSheetItem.Builder()
.setAdapter(adapter)
@@ -191,7 +223,7 @@ public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDial
GradientDrawable background = (GradientDrawable) AppCompatResources.getDrawable(app,
R.drawable.bg_select_group_button_outline);
if (background != null) {
- int highlightColor = ContextCompat.getColor(app,nightMode ?
+ int highlightColor = ContextCompat.getColor(app, nightMode ?
R.color.list_background_color_dark : R.color.activity_background_color_light);
int strokedColor = AndroidUtils.getColorFromAttr(UiUtilities.getThemedContext(app, nightMode),
R.attr.stroked_buttons_and_links_outline);
@@ -234,7 +266,7 @@ public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDial
}
public static void showInstance(@NonNull FragmentManager fm, @Nullable Fragment targetFragment, String folderName,
- String fileName, boolean showSimplifiedButton, boolean showOnMap) {
+ String fileName, boolean showSimplifiedButton, boolean showOnMap) {
try {
if (!fm.isStateSaved()) {
SaveAsNewTrackBottomSheetDialogFragment fragment = new SaveAsNewTrackBottomSheetDialogFragment();
@@ -284,7 +316,7 @@ public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDial
}
}
}
- GPXUtilities.GPXFile gpxFile = GPXUtilities.loadGPXFile(dest);
+ GPXFile gpxFile = GPXUtilities.loadGPXFile(dest);
if (gpxFile.error != null) {
return;
}
@@ -331,6 +363,38 @@ public class SaveAsNewTrackBottomSheetDialogFragment extends MenuBottomSheetDial
return false;
}
+ private List getFolders() {
+ List dirs = new ArrayList<>();
+ File gpxDir = app.getAppPath(IndexConstants.GPX_INDEX_DIR);
+ dirs.add(gpxDir);
+ Algorithms.collectDirs(gpxDir, dirs);
+ List dirItems = new ArrayList<>();
+ for (File dir : dirs) {
+ dirItems.add(dir.getName());
+ }
+ return dirItems;
+ }
+
+ @Override
+ public void onFileMove(@NonNull File src, @NonNull File dest) {
+ File destFolder = dest.getParentFile();
+ if (destFolder != null) {
+ folderName = destFolder.getName();
+ boolean newFolder = destFolder.mkdirs();
+ List folders = getFolders();
+ if (newFolder) {
+ adapter.setFolders(folders);
+ }
+ adapter.setSelectedFolderName(folderName);
+ adapter.notifyDataSetChanged();
+
+ int position = folders.indexOf(folderName);
+ if (position != -1) {
+ recyclerView.scrollToPosition(position);
+ }
+ }
+ }
+
@Override
protected int getBgColorId() {
return nightMode ? R.color.activity_background_color_dark : R.color.list_background_color_light;
diff --git a/OsmAnd/src/net/osmand/plus/measurementtool/adapter/FolderListAdapter.java b/OsmAnd/src/net/osmand/plus/measurementtool/adapter/FolderListAdapter.java
index b383a4bef6..30b85910ad 100644
--- a/OsmAnd/src/net/osmand/plus/measurementtool/adapter/FolderListAdapter.java
+++ b/OsmAnd/src/net/osmand/plus/measurementtool/adapter/FolderListAdapter.java
@@ -15,14 +15,11 @@ import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import net.osmand.AndroidUtils;
-import net.osmand.IndexConstants;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.util.Algorithms;
-import java.io.File;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
public class FolderListAdapter extends RecyclerView.Adapter {
@@ -38,24 +35,15 @@ public class FolderListAdapter extends RecyclerView.Adapter folders) {
items.clear();
- items.addAll(getFolders());
- }
-
- private Collection extends String> getFolders() {
- List dirs = new ArrayList<>();
- File gpxDir = app.getAppPath(IndexConstants.GPX_INDEX_DIR);
- dirs.add(gpxDir);
- Algorithms.collectDirs(gpxDir, dirs);
- List dirItems = new ArrayList<>();
- for (File dir : dirs) {
- dirItems.add(dir.getName());
- }
- return dirItems;
+ items.addAll(folders);
}
@NonNull
diff --git a/OsmAnd/src/net/osmand/plus/myplaces/AddNewTrackFolderBottomSheet.java b/OsmAnd/src/net/osmand/plus/myplaces/AddNewTrackFolderBottomSheet.java
new file mode 100644
index 0000000000..2a80de5b43
--- /dev/null
+++ b/OsmAnd/src/net/osmand/plus/myplaces/AddNewTrackFolderBottomSheet.java
@@ -0,0 +1,158 @@
+package net.osmand.plus.myplaces;
+
+import android.content.res.ColorStateList;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+
+import com.google.android.material.textfield.TextInputEditText;
+import com.google.android.material.textfield.TextInputLayout;
+
+import net.osmand.AndroidUtils;
+import net.osmand.IndexConstants;
+import net.osmand.PlatformUtil;
+import net.osmand.plus.OsmandApplication;
+import net.osmand.plus.R;
+import net.osmand.plus.UiUtilities;
+import net.osmand.plus.base.MenuBottomSheetDialogFragment;
+import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
+import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
+import net.osmand.util.Algorithms;
+
+import org.apache.commons.logging.Log;
+
+import java.io.File;
+
+import static net.osmand.FileUtils.ILLEGAL_PATH_NAME_CHARACTERS;
+
+public class AddNewTrackFolderBottomSheet extends MenuBottomSheetDialogFragment {
+
+ public static final String TAG = AddNewTrackFolderBottomSheet.class.getName();
+ private static final Log LOG = PlatformUtil.getLog(AddNewTrackFolderBottomSheet.class);
+ private static final String FOLDER_NAME_KEY = "folder_name_key";
+
+ private OsmandApplication app;
+
+ private TextInputEditText editText;
+ private TextInputLayout nameTextBox;
+
+ private String folderName;
+ private boolean rightButtonEnabled = true;
+
+ @Override
+ public void createMenuItems(Bundle savedInstanceState) {
+ app = requiredMyApplication();
+ if (savedInstanceState != null) {
+ folderName = savedInstanceState.getString(FOLDER_NAME_KEY);
+ } else if (Algorithms.isEmpty(folderName)) {
+ folderName = app.getAppPath(IndexConstants.GPX_INDEX_DIR).getName();
+ }
+ items.add(new TitleItem(getString(R.string.add_new_folder)));
+
+ View view = UiUtilities.getInflater(app, nightMode).inflate(R.layout.track_name_edit_text, null);
+ nameTextBox = view.findViewById(R.id.name_text_box);
+ nameTextBox.setBoxBackgroundColorResource(nightMode ? R.color.list_background_color_dark : R.color.activity_background_color_light);
+ nameTextBox.setHint(AndroidUtils.addColon(app, R.string.shared_string_name));
+ ColorStateList colorStateList = ColorStateList.valueOf(ContextCompat
+ .getColor(app, nightMode ? R.color.text_color_secondary_dark : R.color.text_color_secondary_light));
+ nameTextBox.setDefaultHintTextColor(colorStateList);
+ editText = view.findViewById(R.id.name_edit_text);
+ editText.setText(folderName);
+ editText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ updateFileNameFromEditText(s.toString());
+ }
+ });
+ BaseBottomSheetItem editFolderName = new BaseBottomSheetItem.Builder()
+ .setCustomView(view)
+ .create();
+ items.add(editFolderName);
+ }
+
+ @Override
+ protected boolean isRightBottomButtonEnabled() {
+ return rightButtonEnabled;
+ }
+
+ private void updateFileNameFromEditText(String name) {
+ rightButtonEnabled = false;
+ if (ILLEGAL_PATH_NAME_CHARACTERS.matcher(name).find()) {
+ nameTextBox.setError(getString(R.string.file_name_containes_illegal_char));
+ } else if (Algorithms.isEmpty(name.trim())) {
+ nameTextBox.setError(getString(R.string.empty_filename));
+ } else {
+ File destFolder = new File(app.getAppPath(IndexConstants.GPX_INDEX_DIR), name);
+ if (destFolder.exists()) {
+ nameTextBox.setError(getString(R.string.file_with_name_already_exist));
+ } else {
+ nameTextBox.setError(null);
+ folderName = name;
+ rightButtonEnabled = true;
+ }
+ }
+ updateBottomButtons();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ outState.putString(FOLDER_NAME_KEY, folderName);
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onRightBottomButtonClick() {
+ AndroidUtils.hideSoftKeyboard(requireActivity(), editText);
+ Fragment fragment = getTargetFragment();
+ if (fragment instanceof OnTrackFolderAddListener) {
+ OnTrackFolderAddListener listener = (OnTrackFolderAddListener) fragment;
+ listener.onTrackFolderAdd(folderName);
+ }
+ dismiss();
+ }
+
+ @Override
+ protected int getDismissButtonTextId() {
+ return R.string.shared_string_cancel;
+ }
+
+ @Override
+ protected int getRightBottomButtonTextId() {
+ return R.string.shared_string_add;
+ }
+
+ public interface OnTrackFolderAddListener {
+
+ void onTrackFolderAdd(String folderName);
+ }
+
+ public static void showInstance(@NonNull FragmentManager fragmentManager, @Nullable Fragment target,
+ @NonNull String folderName, boolean usedOnMap) {
+ try {
+ if (!fragmentManager.isStateSaved() && fragmentManager.findFragmentByTag(AddNewTrackFolderBottomSheet.TAG) == null) {
+ AddNewTrackFolderBottomSheet fragment = new AddNewTrackFolderBottomSheet();
+ fragment.folderName = folderName;
+ fragment.setUsedOnMap(usedOnMap);
+ fragment.setTargetFragment(target, 0);
+ fragment.show(fragmentManager, AddNewTrackFolderBottomSheet.TAG);
+ }
+ } catch (RuntimeException e) {
+ LOG.error("showInstance", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/OsmAnd/src/net/osmand/plus/myplaces/AvailableGPXFragment.java b/OsmAnd/src/net/osmand/plus/myplaces/AvailableGPXFragment.java
index 9e4ac656a4..06a38d3ef2 100644
--- a/OsmAnd/src/net/osmand/plus/myplaces/AvailableGPXFragment.java
+++ b/OsmAnd/src/net/osmand/plus/myplaces/AvailableGPXFragment.java
@@ -42,6 +42,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.view.ActionMode;
import androidx.appcompat.widget.SearchView;
import androidx.core.content.ContextCompat;
+import androidx.fragment.app.FragmentActivity;
import net.osmand.AndroidUtils;
import net.osmand.Collator;
@@ -81,11 +82,12 @@ import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType;
import net.osmand.plus.helpers.enums.TracksSortByMode;
import net.osmand.plus.mapmarkers.CoordinateInputDialogFragment;
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
+import net.osmand.plus.myplaces.MoveGpxFileBottomSheet.OnTrackFileMoveListener;
import net.osmand.plus.osmedit.OsmEditingPlugin;
import net.osmand.plus.osmedit.oauth.OsmOAuthHelper.OsmAuthorizationListener;
import net.osmand.plus.settings.backend.OsmandSettings;
-import net.osmand.plus.widgets.popup.PopUpMenuItem;
import net.osmand.plus.widgets.popup.PopUpMenuHelper;
+import net.osmand.plus.widgets.popup.PopUpMenuItem;
import java.io.File;
import java.text.DateFormat;
@@ -105,6 +107,7 @@ import java.util.regex.Pattern;
import static net.osmand.plus.GpxSelectionHelper.CURRENT_TRACK;
import static net.osmand.plus.myplaces.FavoritesActivity.GPX_TAB;
+import static net.osmand.plus.myplaces.FavoritesActivity.OPEN_GPX_REQUEST;
import static net.osmand.plus.myplaces.FavoritesActivity.TAB_ID;
import static net.osmand.util.Algorithms.capitalizeFirstLetter;
import static net.osmand.util.Algorithms.collectDirs;
@@ -113,9 +116,8 @@ import static net.osmand.util.Algorithms.objectEquals;
import static net.osmand.util.Algorithms.removeAllFiles;
public class AvailableGPXFragment extends OsmandExpandableListFragment implements
- FavoritesFragmentStateHolder, OsmAuthorizationListener {
+ FavoritesFragmentStateHolder, OsmAuthorizationListener, OnTrackFileMoveListener, RenameCallback {
- public static final Pattern ILLEGAL_PATH_NAME_CHARACTERS = Pattern.compile("[?:\"*|<>]");
public static final int SEARCH_ID = -1;
// public static final int ACTION_ID = 0;
// protected static final int DELETE_ACTION_ID = 1;
@@ -426,7 +428,7 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
newIntent.putExtra(TrackActivity.TRACK_FILE_NAME, f.getAbsolutePath());
}
newIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- a.startActivity(newIntent);
+ a.startActivityForResult(newIntent, OPEN_GPX_REQUEST);
}
public void reloadTracks() {
@@ -434,6 +436,10 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
asyncLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getActivity());
}
+ public void resetTracksLoader() {
+ asyncLoader = null;
+ }
+
@Override
public void onCreateOptionsMenu(Menu menu, @NonNull MenuInflater inflater) {
menu.clear();
@@ -790,129 +796,10 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
}
private void moveGpx(final GpxInfo info) {
-
- final ContextMenuAdapter menuAdapter = new ContextMenuAdapter(app);
- ContextMenuItem.ItemBuilder itemBuilder = new ContextMenuItem.ItemBuilder();
-
- final List dirs = new ArrayList<>();
- collectDirs(app.getAppPath(IndexConstants.GPX_INDEX_DIR), dirs, info.file.getParentFile());
- if (!info.file.getParentFile().equals(app.getAppPath(IndexConstants.GPX_INDEX_DIR))) {
- dirs.add(0, app.getAppPath(IndexConstants.GPX_INDEX_DIR));
+ FragmentActivity activity = getActivity();
+ if (activity != null) {
+ MoveGpxFileBottomSheet.showInstance(activity.getSupportFragmentManager(), this, info.file.getAbsolutePath(), false);
}
- String gpxDir = app.getAppPath(IndexConstants.GPX_INDEX_DIR).getPath();
- int i = 0;
- for (File dir : dirs) {
- String dirName = dir.getPath();
- if (dirName.startsWith(gpxDir)) {
- if (dirName.length() == gpxDir.length()) {
- dirName = dir.getName();
- } else {
- dirName = dirName.substring(gpxDir.length() + 1);
- }
- }
- menuAdapter.addItem(itemBuilder.setTitle(capitalizeFirstLetter(dirName))
- .setIcon(R.drawable.ic_action_folder_stroke).setTag(i).createItem());
- i++;
- }
- menuAdapter.addItem(itemBuilder.setTitleId(R.string.add_new_folder, app)
- .setIcon(R.drawable.ic_zoom_in).setTag(-1).createItem());
- final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- final ArrayAdapter listAdapter =
- menuAdapter.createListAdapter(getActivity(), app.getSettings().isLightContent());
- builder.setTitle(R.string.select_gpx_folder);
- builder.setAdapter(listAdapter, new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- ContextMenuItem item = menuAdapter.getItem(which);
- int index = item.getTag();
- if (index == -1) {
- Activity a = getActivity();
- AlertDialog.Builder b = new AlertDialog.Builder(a);
- b.setTitle(R.string.add_new_folder);
- final EditText editText = new EditText(a);
- editText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- Editable text = editText.getText();
- if (text.length() >= 1) {
- if (ILLEGAL_PATH_NAME_CHARACTERS.matcher(text).find()) {
- editText.setError(app.getString(R.string.file_name_containes_illegal_char));
- }
- }
- }
- });
- int leftPadding = AndroidUtils.dpToPx(a, 24f);
- int topPadding = AndroidUtils.dpToPx(a, 4f);
- b.setView(editText, leftPadding, topPadding, leftPadding, topPadding);
- // Behaviour will be overwritten later;
- b.setPositiveButton(R.string.shared_string_ok, null);
- b.setNegativeButton(R.string.shared_string_cancel, null);
- final AlertDialog alertDialog = b.create();
- alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
- @Override
- public void onShow(DialogInterface dialog) {
- alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- String newName = editText.getText().toString();
- if (ILLEGAL_PATH_NAME_CHARACTERS.matcher(newName).find()) {
- Toast.makeText(app, R.string.file_name_containes_illegal_char,
- Toast.LENGTH_LONG).show();
- return;
- }
- File destFolder = new File(app.getAppPath(IndexConstants.GPX_INDEX_DIR), newName);
- if (destFolder.exists()) {
- Toast.makeText(app, R.string.file_with_name_already_exists,
- Toast.LENGTH_LONG).show();
- return;
- } else if (destFolder.mkdirs()) {
- File dest = new File(destFolder, info.fileName);
- if (info.file.renameTo(dest)) {
- app.getGpxDbHelper().rename(info.file, dest);
- asyncLoader = new LoadGpxTask();
- asyncLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getActivity());
- } else {
- Toast.makeText(app, R.string.file_can_not_be_moved, Toast.LENGTH_LONG).show();
- }
-
- } else {
- Toast.makeText(app, R.string.file_can_not_be_moved, Toast.LENGTH_LONG).show();
- }
- alertDialog.dismiss();
- }
- });
- }
- });
- alertDialog.show();
- } else {
- File dir = dirs.get(index);
- File dest = new File(dir, info.file.getName());
- if (dest.exists()) {
- Toast.makeText(app, R.string.file_with_name_already_exists, Toast.LENGTH_LONG).show();
- } else {
- if (info.file.renameTo(dest)) {
- app.getGpxDbHelper().rename(info.file, dest);
- asyncLoader = new LoadGpxTask();
- asyncLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getActivity());
- } else {
- Toast.makeText(app, R.string.file_can_not_be_moved, Toast.LENGTH_LONG).show();
- }
- }
- }
- }
- });
- builder.setNegativeButton(R.string.shared_string_cancel, null);
- builder.create().show();
}
@Override
@@ -938,6 +825,26 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
app.startActivity(intent);
}
+ @Override
+ public void onFileMove(@NonNull File src, @NonNull File dest) {
+ File destFolder = dest.getParentFile();
+ if (destFolder != null && !destFolder.exists() && !destFolder.mkdirs()) {
+ app.showToastMessage(R.string.file_can_not_be_moved);
+ } else if (dest.exists()) {
+ app.showToastMessage(R.string.file_with_name_already_exists);
+ } else if (src.renameTo(dest)) {
+ app.getGpxDbHelper().rename(src, dest);
+ asyncLoader = new LoadGpxTask();
+ asyncLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getActivity());
+ } else {
+ app.showToastMessage(R.string.file_can_not_be_moved);
+ }
+ }
+
+ public void renamedTo(File file) {
+ reloadTracks();
+ }
+
public class LoadGpxTask extends AsyncTask> {
private List result;
@@ -1543,13 +1450,10 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- FileUtils.renameFile(getActivity(), gpxInfo.file, new RenameCallback() {
- @Override
- public void renamedTo(File file) {
- asyncLoader = new LoadGpxTask();
- asyncLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getActivity());
- }
- });
+ FragmentActivity activity = getActivity();
+ if (activity != null) {
+ FileUtils.renameFile(activity, gpxInfo.file, AvailableGPXFragment.this, false);
+ }
}
})
.create()
@@ -1711,20 +1615,7 @@ public class AvailableGPXFragment extends OsmandExpandableListFragment implement
GpxInfo item = allGpxAdapter.getChild(groupPosition, childPosition);
if (!selectionMode) {
- Intent newIntent = new Intent(getActivity(), getMyApplication().getAppCustomization().getTrackActivity());
- // causes wrong position caching: newIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
- if (item.currentlyRecordingTrack) {
- newIntent.putExtra(TrackActivity.CURRENT_RECORDING, true);
- } else {
- newIntent.putExtra(TrackActivity.TRACK_FILE_NAME, item.file.getAbsolutePath());
- }
- newIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(newIntent);
- // item.setExpanded(!item.isExpanded());
- // if (item.isExpanded()) {
- // descriptionLoader = new LoadLocalIndexDescriptionTask();
- // descriptionLoader.execute(item);
- // }
+ openTrack(getActivity(), item.file);
} else {
if (!selectedItems.contains(item)) {
selectedItems.add(item);
diff --git a/OsmAnd/src/net/osmand/plus/myplaces/FavoritesActivity.java b/OsmAnd/src/net/osmand/plus/myplaces/FavoritesActivity.java
index 43e1e73cc8..c4e5cc8cee 100644
--- a/OsmAnd/src/net/osmand/plus/myplaces/FavoritesActivity.java
+++ b/OsmAnd/src/net/osmand/plus/myplaces/FavoritesActivity.java
@@ -42,6 +42,8 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
+import static net.osmand.plus.myplaces.TrackSegmentFragment.TRACK_DELETED_KEY;
+
/**
*
*/
@@ -50,6 +52,7 @@ public class FavoritesActivity extends TabActivity {
private static final int OPEN_GPX_DOCUMENT_REQUEST = 1006;
private static final int IMPORT_FAVOURITES_REQUEST = 1007;
+ protected static final int OPEN_GPX_REQUEST = 1008;
public static final String TAB_ID = "selected_tab_id";
@@ -152,6 +155,13 @@ public class FavoritesActivity extends TabActivity {
if (data != null && data.getData() != null) {
importHelper.handleGpxOrFavouritesImport(data.getData());
}
+ } else if (requestCode == OPEN_GPX_REQUEST && resultCode == Activity.RESULT_OK) {
+ if (data != null && data.getBooleanExtra(TRACK_DELETED_KEY, false)) {
+ AvailableGPXFragment gpxFragment = getGpxFragment();
+ if (gpxFragment != null) {
+ gpxFragment.resetTracksLoader();
+ }
+ }
} else {
super.onActivityResult(requestCode, resultCode, data);
}
diff --git a/OsmAnd/src/net/osmand/plus/myplaces/MoveGpxFileBottomSheet.java b/OsmAnd/src/net/osmand/plus/myplaces/MoveGpxFileBottomSheet.java
new file mode 100644
index 0000000000..c00e360d7d
--- /dev/null
+++ b/OsmAnd/src/net/osmand/plus/myplaces/MoveGpxFileBottomSheet.java
@@ -0,0 +1,183 @@
+package net.osmand.plus.myplaces;
+
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+
+import net.osmand.IndexConstants;
+import net.osmand.PlatformUtil;
+import net.osmand.plus.OsmandApplication;
+import net.osmand.plus.R;
+import net.osmand.plus.UiUtilities;
+import net.osmand.plus.base.MenuBottomSheetDialogFragment;
+import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
+import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
+import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
+import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerItem;
+import net.osmand.plus.helpers.AndroidUiHelper;
+import net.osmand.plus.myplaces.AddNewTrackFolderBottomSheet.OnTrackFolderAddListener;
+import net.osmand.util.Algorithms;
+
+import org.apache.commons.logging.Log;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import static net.osmand.util.Algorithms.capitalizeFirstLetter;
+import static net.osmand.util.Algorithms.collectDirs;
+
+public class MoveGpxFileBottomSheet extends MenuBottomSheetDialogFragment implements OnTrackFolderAddListener {
+
+ public static final String TAG = MoveGpxFileBottomSheet.class.getSimpleName();
+ private static final Log LOG = PlatformUtil.getLog(MoveGpxFileBottomSheet.class);
+ private static final String FILE_PATH_KEY = "file_path_key";
+
+ private OsmandApplication app;
+ private String filePath;
+
+ @Override
+ public void createMenuItems(Bundle savedInstanceState) {
+ app = requiredMyApplication();
+ if (savedInstanceState != null) {
+ filePath = savedInstanceState.getString(FILE_PATH_KEY);
+ }
+ if (filePath == null) {
+ return;
+ }
+ final File file = new File(filePath);
+ final File fileDir = file.getParentFile();
+
+ BaseBottomSheetItem titleItem = new BottomSheetItemWithDescription.Builder()
+ .setDescription(getString(R.string.select_folder_descr))
+ .setTitle(getString(R.string.shared_string_folders))
+ .setLayoutId(R.layout.bottom_sheet_item_title_with_description)
+ .create();
+ items.add(titleItem);
+
+ View addNewFolderView = UiUtilities.getInflater(app, nightMode).inflate(R.layout.bottom_sheet_item_with_descr_64dp, null);
+ addNewFolderView.setMinimumHeight(getResources().getDimensionPixelSize(R.dimen.bottom_sheet_list_item_height));
+ AndroidUiHelper.updateVisibility(addNewFolderView.findViewById(R.id.description), false);
+ BaseBottomSheetItem addNewFolderItem = new SimpleBottomSheetItem.Builder()
+ .setTitle(getString(R.string.add_new_folder))
+ .setIcon(getActiveIcon(R.drawable.ic_action_folder_add))
+ .setLayoutId(R.layout.bottom_sheet_item_with_descr_64dp)
+ .setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FragmentActivity activity = getActivity();
+ if (activity != null) {
+ AddNewTrackFolderBottomSheet.showInstance(activity.getSupportFragmentManager(),
+ MoveGpxFileBottomSheet.this, fileDir.getName(), usedOnMap);
+ }
+ }
+ })
+ .setCustomView(addNewFolderView)
+ .create();
+ items.add(addNewFolderItem);
+
+ DividerItem dividerItem = new DividerItem(app);
+ dividerItem.setMargins(0, 0, 0, 0);
+ items.add(dividerItem);
+
+ final List dirs = new ArrayList<>();
+ collectDirs(app.getAppPath(IndexConstants.GPX_INDEX_DIR), dirs, fileDir);
+ if (!Algorithms.objectEquals(fileDir, app.getAppPath(IndexConstants.GPX_INDEX_DIR))) {
+ dirs.add(0, app.getAppPath(IndexConstants.GPX_INDEX_DIR));
+ }
+ String gpxDir = app.getAppPath(IndexConstants.GPX_INDEX_DIR).getPath();
+ for (final File dir : dirs) {
+ String dirName = dir.getPath();
+ if (dirName.startsWith(gpxDir)) {
+ if (dirName.length() == gpxDir.length()) {
+ dirName = dir.getName();
+ } else {
+ dirName = dirName.substring(gpxDir.length() + 1);
+ }
+ }
+ String description;
+ List files = collectFiles(dir);
+ if (Algorithms.isEmpty(files)) {
+ description = getString(R.string.shared_string_empty);
+ } else {
+ description = String.valueOf(files.size());
+ }
+ final BaseBottomSheetItem[] folderItem = new BaseBottomSheetItem[1];
+ folderItem[0] = new BottomSheetItemWithDescription.Builder()
+ .setDescription(description)
+ .setTitle(capitalizeFirstLetter(dirName))
+ .setIcon(getActiveIcon(R.drawable.ic_action_folder))
+ .setLayoutId(R.layout.bottom_sheet_item_with_descr_64dp)
+ .setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Fragment fragment = getTargetFragment();
+ if (fragment instanceof OnTrackFileMoveListener) {
+ OnTrackFileMoveListener listener = (OnTrackFileMoveListener) fragment;
+ listener.onFileMove(file, new File(dir, file.getName()));
+ }
+ dismiss();
+ }
+ })
+ .setTag(dir)
+ .create();
+ items.add(folderItem[0]);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putString(FILE_PATH_KEY, filePath);
+ }
+
+ @Override
+ public void onTrackFolderAdd(String folderName) {
+ Fragment fragment = getTargetFragment();
+ if (fragment instanceof OnTrackFileMoveListener) {
+ File file = new File(filePath);
+ File destFolder = new File(app.getAppPath(IndexConstants.GPX_INDEX_DIR), folderName);
+ OnTrackFileMoveListener listener = (OnTrackFileMoveListener) fragment;
+ listener.onFileMove(file, new File(destFolder, file.getName()));
+ }
+ dismiss();
+ }
+
+ public List collectFiles(File parentDir) {
+ List files = new ArrayList<>();
+ File[] listFiles = parentDir.listFiles();
+ if (listFiles != null) {
+ for (File file : listFiles) {
+ if (!file.isDirectory()) {
+ files.add(file);
+ }
+ }
+ }
+ return files;
+ }
+
+ public static void showInstance(@NonNull FragmentManager fragmentManager, @Nullable Fragment target,
+ @NonNull String filePath, boolean usedOnMap) {
+ try {
+ if (!fragmentManager.isStateSaved() && fragmentManager.findFragmentByTag(MoveGpxFileBottomSheet.TAG) == null) {
+ MoveGpxFileBottomSheet fragment = new MoveGpxFileBottomSheet();
+ fragment.filePath = filePath;
+ fragment.setUsedOnMap(usedOnMap);
+ fragment.setTargetFragment(target, 0);
+ fragment.show(fragmentManager, MoveGpxFileBottomSheet.TAG);
+ }
+ } catch (RuntimeException e) {
+ LOG.error("showInstance", e);
+ }
+ }
+
+ public interface OnTrackFileMoveListener {
+ void onFileMove(@NonNull File src, @NonNull File dest);
+ }
+}
\ No newline at end of file
diff --git a/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java b/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java
index 4541cf810a..4a66e09d99 100644
--- a/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java
+++ b/OsmAnd/src/net/osmand/plus/myplaces/TrackSegmentFragment.java
@@ -1,6 +1,8 @@
package net.osmand.plus.myplaces;
+import android.app.Activity;
import android.content.DialogInterface;
+import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
@@ -23,6 +25,8 @@ import androidx.fragment.app.FragmentManager;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import net.osmand.AndroidUtils;
+import net.osmand.FileUtils;
+import net.osmand.FileUtils.RenameCallback;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.Track;
import net.osmand.GPXUtilities.TrkSegment;
@@ -53,7 +57,10 @@ import java.io.File;
import java.util.ArrayList;
import java.util.List;
-public class TrackSegmentFragment extends OsmAndListFragment implements TrackBitmapDrawerListener, SegmentActionsListener {
+public class TrackSegmentFragment extends OsmAndListFragment implements TrackBitmapDrawerListener,
+ SegmentActionsListener, RenameCallback {
+
+ public static final String TRACK_DELETED_KEY = "track_deleted_key";
private OsmandApplication app;
private TrackDisplayHelper displayHelper;
@@ -134,8 +141,40 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
}
});
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
- }
- if (gpxFile.showCurrentTrack) {
+ MenuItem renameItem = menu.add(R.string.shared_string_rename)
+ .setIcon(app.getUIUtilities().getIcon((R.drawable.ic_action_edit_dark)))
+ .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ GPXFile gpx = displayHelper.getGpx();
+ FragmentActivity activity = getActivity();
+ if (activity != null && gpx != null) {
+ FileUtils.renameFile(activity, new File(gpx.path), TrackSegmentFragment.this, false);
+ }
+ return true;
+ }
+ });
+ renameItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ MenuItem deleteItem = menu.add(R.string.shared_string_delete)
+ .setIcon(app.getUIUtilities().getIcon((R.drawable.ic_action_delete_dark)))
+ .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ GPXFile gpx = displayHelper.getGpx();
+ FragmentActivity activity = getActivity();
+ if (activity != null && gpx != null) {
+ if (FileUtils.removeGpxFile(app, new File((gpx.path)))) {
+ Intent intent = new Intent();
+ intent.putExtra(TRACK_DELETED_KEY, true);
+ activity.setResult(Activity.RESULT_OK, intent);
+ activity.onBackPressed();
+ }
+ }
+ return true;
+ }
+ });
+ deleteItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+ } else if (gpxFile.showCurrentTrack) {
MenuItem item = menu.add(R.string.shared_string_refresh).setIcon(R.drawable.ic_action_refresh_dark)
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
@@ -415,4 +454,14 @@ public class TrackSegmentFragment extends OsmAndListFragment implements TrackBit
}
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
+
+ @Override
+ public void renamedTo(File file) {
+ displayHelper.setFile(file);
+ TrackActivity activity = getTrackActivity();
+ if (activity != null) {
+ activity.setupActionBar();
+ activity.loadGpx();
+ }
+ }
}
\ No newline at end of file
diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/EngineType.java b/OsmAnd/src/net/osmand/plus/onlinerouting/EngineType.java
new file mode 100644
index 0000000000..fe5080f14c
--- /dev/null
+++ b/OsmAnd/src/net/osmand/plus/onlinerouting/EngineType.java
@@ -0,0 +1,24 @@
+package net.osmand.plus.onlinerouting;
+
+public enum EngineType {
+
+ GRAPHHOPPER("Graphhopper", "https://graphhopper.com/api/1/route"),
+ OSRM("OSRM", "https://router.project-osrm.org/route/v1/"),
+ ORS("Openroute Service", "https://api.openrouteservice.org/v2/directions/");
+
+ private String title;
+ private String standardUrl;
+
+ EngineType(String title, String standardUrl) {
+ this.title = title;
+ this.standardUrl = standardUrl;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getStandardUrl() {
+ return standardUrl;
+ }
+}
diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngine.java b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngine.java
index aae11a39b9..3193d86d09 100644
--- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngine.java
+++ b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngine.java
@@ -15,32 +15,32 @@ public class OnlineRoutingEngine {
public final static String ONLINE_ROUTING_ENGINE_PREFIX = "online_routing_engine_";
- public enum EngineParameterType {
- CUSTOM_SERVER_URL,
+ public enum EngineParameter {
CUSTOM_NAME,
+ CUSTOM_URL,
API_KEY
}
private String stringKey;
- private ServerType serverType;
+ private EngineType type;
private String vehicleKey;
private Map params = new HashMap<>();
public OnlineRoutingEngine(@NonNull String stringKey,
- @NonNull ServerType serverType,
- @NonNull String vehicleKey,
- @Nullable Map params) {
- this(stringKey, serverType, vehicleKey);
+ @NonNull EngineType type,
+ @NonNull String vehicleKey,
+ @Nullable Map params) {
+ this(stringKey, type, vehicleKey);
if (!Algorithms.isEmpty(params)) {
this.params.putAll(params);
}
}
public OnlineRoutingEngine(@NonNull String stringKey,
- @NonNull ServerType serverType,
+ @NonNull EngineType type,
@NonNull String vehicleKey) {
this.stringKey = stringKey;
- this.serverType = serverType;
+ this.type = type;
this.vehicleKey = vehicleKey;
}
@@ -48,8 +48,16 @@ public class OnlineRoutingEngine {
return stringKey;
}
- public ServerType getServerType() {
- return serverType;
+ public EngineType getType() {
+ return type;
+ }
+
+ public String getBaseUrl() {
+ String customUrl = getParameter(EngineParameter.CUSTOM_URL);
+ if (Algorithms.isEmpty(customUrl)) {
+ return type.getStandardUrl();
+ }
+ return customUrl;
}
public String getVehicleKey() {
@@ -60,25 +68,16 @@ public class OnlineRoutingEngine {
return params;
}
- public String getBaseUrl() {
- String customServerUrl = getParameter(EngineParameterType.CUSTOM_SERVER_URL);
- if (!Algorithms.isEmpty(customServerUrl)) {
- return customServerUrl;
- } else {
- return serverType.getBaseUrl();
- }
+ public String getParameter(EngineParameter paramKey) {
+ return params.get(paramKey.name());
}
- public String getParameter(EngineParameterType paramType) {
- return params.get(paramType.name());
- }
-
- public void putParameter(EngineParameterType paramType, String paramValue) {
- params.put(paramType.name(), paramValue);
+ public void putParameter(EngineParameter paramKey, String paramValue) {
+ params.put(paramKey.name(), paramValue);
}
public String getName(@NonNull Context ctx) {
- String customName = getParameter(EngineParameterType.CUSTOM_NAME);
+ String customName = getParameter(EngineParameter.CUSTOM_NAME);
if (customName != null) {
return customName;
} else {
@@ -87,21 +86,21 @@ public class OnlineRoutingEngine {
}
private String getStandardName(@NonNull Context ctx) {
- return getStandardName(ctx, serverType, vehicleKey);
+ return getStandardName(ctx, type, vehicleKey);
}
public static String getStandardName(@NonNull Context ctx,
- @NonNull ServerType serverType,
+ @NonNull EngineType type,
@NonNull String vehicleKey) {
String vehicleTitle = VehicleType.toHumanString(ctx, vehicleKey);
String pattern = ctx.getString(R.string.ltr_or_rtl_combine_via_dash);
- return String.format(pattern, serverType.getTitle(), vehicleTitle);
+ return String.format(pattern, type.getTitle(), vehicleTitle);
}
- public static OnlineRoutingEngine createNewEngine(@NonNull ServerType serverType,
- @NonNull String vehicleKey,
- @Nullable Map params) {
- return new OnlineRoutingEngine(generateKey(), serverType, vehicleKey, params);
+ public static OnlineRoutingEngine createNewEngine(@NonNull EngineType type,
+ @NonNull String vehicleKey,
+ @Nullable Map params) {
+ return new OnlineRoutingEngine(generateKey(), type, vehicleKey, params);
}
private static String generateKey() {
diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngineFragment.java b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngineFragment.java
index 46e47bc8f2..59df4ef698 100644
--- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngineFragment.java
+++ b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngineFragment.java
@@ -30,7 +30,7 @@ import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionItem;
import net.osmand.plus.onlinerouting.OnlineRoutingCard.OnTextChangedListener;
-import net.osmand.plus.onlinerouting.OnlineRoutingEngine.EngineParameterType;
+import net.osmand.plus.onlinerouting.OnlineRoutingEngine.EngineParameter;
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.util.Algorithms;
@@ -62,7 +62,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
private View view;
private ViewGroup segmentsContainer;
private OnlineRoutingCard nameCard;
- private OnlineRoutingCard serverCard;
+ private OnlineRoutingCard typeCard;
private OnlineRoutingCard vehicleCard;
private OnlineRoutingCard apiKeyCard;
private OnlineRoutingCard exampleCard;
@@ -132,8 +132,8 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
- @Nullable ViewGroup container,
- @Nullable Bundle savedInstanceState) {
+ @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
view = getInflater().inflate(
R.layout.online_routing_engine_fragment, container, false);
segmentsContainer = (ViewGroup) view.findViewById(R.id.segments_container);
@@ -143,7 +143,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
setupToolbar((Toolbar) view.findViewById(R.id.toolbar));
setupNameCard();
- setupServerCard();
+ setupTypeCard();
setupVehicleCard();
setupApiKeyCard();
setupExampleCard();
@@ -152,7 +152,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
setupButtons();
- updateCardViews(nameCard, serverCard, vehicleCard, exampleCard);
+ updateCardViews(nameCard, typeCard, vehicleCard, exampleCard);
return view;
}
@@ -174,38 +174,39 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
segmentsContainer.addView(nameCard.getView());
}
- private void setupServerCard() {
- serverCard = new OnlineRoutingCard(mapActivity, isNightMode());
- serverCard.build(mapActivity);
- serverCard.setHeaderTitle(getString(R.string.shared_string_type));
+ private void setupTypeCard() {
+ typeCard = new OnlineRoutingCard(mapActivity, isNightMode());
+ typeCard.build(mapActivity);
+ typeCard.setHeaderTitle(getString(R.string.shared_string_type));
List serverItems = new ArrayList<>();
- for (ServerType server : ServerType.values()) {
+ for (EngineType server : EngineType.values()) {
serverItems.add(new HorizontalSelectionItem(server.getTitle(), server));
}
- serverCard.setSelectionMenu(serverItems, engine.serverType.getTitle(),
+ typeCard.setSelectionMenu(serverItems, engine.type.getTitle(),
new CallbackWithObject() {
@Override
public boolean processResult(HorizontalSelectionItem result) {
- ServerType server = (ServerType) result.getObject();
- if (engine.serverType != server) {
- engine.serverType = server;
- updateCardViews(nameCard, serverCard, exampleCard);
+ EngineType type = (EngineType) result.getObject();
+ if (engine.type != type) {
+ engine.type = type;
+ updateCardViews(nameCard, typeCard, exampleCard);
return true;
}
return false;
}
});
- serverCard.setOnTextChangedListener(new OnTextChangedListener() {
+ typeCard.setOnTextChangedListener(new OnTextChangedListener() {
@Override
public void onTextChanged(boolean editedByUser, String text) {
if (editedByUser) {
engine.customServerUrl = text;
+ updateCardViews(exampleCard);
}
}
});
- serverCard.setFieldBoxLabelText(getString(R.string.shared_string_server_url));
- serverCard.showDivider();
- segmentsContainer.addView(serverCard.getView());
+ typeCard.setFieldBoxLabelText(getString(R.string.shared_string_server_url));
+ typeCard.showDivider();
+ segmentsContainer.addView(typeCard.getView());
}
private void setupVehicleCard() {
@@ -342,22 +343,28 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
for (BaseCard card : cardsToUpdate) {
if (nameCard.equals(card)) {
if (Algorithms.isEmpty(engine.customName)) {
- String name = OnlineRoutingEngine.getStandardName(app, engine.serverType, engine.getVehicleKey());
+ String name;
+ if (Algorithms.isEmpty(engine.getVehicleKey())) {
+ name = engine.type.getTitle();
+ } else {
+ name = OnlineRoutingEngine.getStandardName(app, engine.type, engine.getVehicleKey());
+ }
nameCard.setEditedText(name);
}
- } else if (serverCard.equals(card)) {
- serverCard.setHeaderSubtitle(engine.serverType.getTitle());
- serverCard.setEditedText(engine.getBaseUrl());
- if (engine.serverType == ServerType.GRAPHHOPER) {
+ } else if (typeCard.equals(card)) {
+ typeCard.setHeaderSubtitle(engine.type.getTitle());
+ typeCard.setEditedText(engine.getBaseUrl());
+ if (engine.type == EngineType.GRAPHHOPPER || engine.type == EngineType.ORS) {
apiKeyCard.show();
} else {
apiKeyCard.hide();
}
} else if (vehicleCard.equals(card)) {
- vehicleCard.setHeaderSubtitle(engine.vehicleType.getTitle(app));
- if (engine.vehicleType == VehicleType.CUSTOM) {
+ VehicleType vt = VehicleType.getVehicleByKey(engine.getVehicleKey());
+ vehicleCard.setHeaderSubtitle(vt.getTitle(app));
+ if (vt == VehicleType.CUSTOM) {
vehicleCard.showFieldBox();
vehicleCard.setEditedText(engine.getVehicleKey());
} else {
@@ -400,15 +407,15 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
private void saveChanges() {
OnlineRoutingEngine engineToSave;
if (isEditingMode()) {
- engineToSave = new OnlineRoutingEngine(editedEngineKey, engine.serverType, engine.getVehicleKey());
+ engineToSave = new OnlineRoutingEngine(editedEngineKey, engine.type, engine.getVehicleKey());
} else {
- engineToSave = OnlineRoutingEngine.createNewEngine(engine.serverType, engine.getVehicleKey(), null);
+ engineToSave = OnlineRoutingEngine.createNewEngine(engine.type, engine.getVehicleKey(), null);
}
- engineToSave.putParameter(EngineParameterType.CUSTOM_SERVER_URL, engine.customServerUrl);
- engineToSave.putParameter(EngineParameterType.CUSTOM_NAME, engine.customName);
- if (engine.serverType == ServerType.GRAPHHOPER) {
- engineToSave.putParameter(EngineParameterType.API_KEY, engine.apiKey);
+ engineToSave.putParameter(EngineParameter.CUSTOM_NAME, engine.customName);
+ engineToSave.putParameter(EngineParameter.CUSTOM_URL, engine.customServerUrl);
+ if (engine.type == EngineType.GRAPHHOPPER || engine.type == EngineType.ORS) {
+ engineToSave.putParameter(EngineParameter.API_KEY, engine.apiKey);
}
helper.saveEngine(engineToSave);
@@ -419,30 +426,18 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
}
private String getTestUrl() {
- String baseUrl = engine.serverType.getBaseUrl();
- String vehicle = engine.getVehicleKey();
-
- LatLon startPoint = selectedLocation.getCityCenterLatLon();
- LatLon endPoint = selectedLocation.getCityAirportLatLon();
-
- if (engine.serverType == ServerType.GRAPHHOPER) {
- return baseUrl + "?" + "point=" + startPoint.getLatitude()
- + "," + startPoint.getLongitude()
- + "&" + "point=" + endPoint.getLatitude()
- + "," + endPoint.getLongitude()
- + "&" + "vehicle=" + vehicle
- + (!Algorithms.isEmpty(engine.apiKey) ? ("&" + "key=" + engine.apiKey) : "");
- } else {
- return baseUrl + vehicle + "/" + startPoint.getLatitude()
- + "," + startPoint.getLongitude()
- + ";" + endPoint.getLatitude()
- + "," + endPoint.getLongitude()
- + "?" + "geometries=geojson";
- }
+ List path = new ArrayList<>();
+ path.add(selectedLocation.getCityCenterLatLon());
+ path.add(selectedLocation.getCityAirportLatLon());
+ OnlineRoutingEngine tmpEngine =
+ OnlineRoutingEngine.createNewEngine(engine.type, engine.getVehicleKey(), null);
+ tmpEngine.putParameter(EngineParameter.CUSTOM_URL, engine.customServerUrl);
+ tmpEngine.putParameter(EngineParameter.API_KEY, engine.apiKey);
+ return helper.createFullUrl(tmpEngine, path);
}
private void testEngineWork() {
- final ServerType server = engine.serverType;
+ final EngineType type = engine.type;
final ExampleLocation location = selectedLocation;
AndroidNetworkUtils.sendRequestAsync(app, exampleCard.getEditedText(), null,
null, false, false, new OnRequestResultListener() {
@@ -453,10 +448,12 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
try {
JSONObject obj = new JSONObject(response);
- if (server == ServerType.GRAPHHOPER) {
+ if (type == EngineType.GRAPHHOPPER) {
resultOk = obj.has("paths");
- } else if (server == ServerType.OSRM) {
+ } else if (type == EngineType.OSRM) {
resultOk = obj.has("routes");
+ } else if (type == EngineType.ORS) {
+ resultOk = obj.has("features");
}
} catch (JSONException e) {
@@ -494,7 +491,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
private void saveState(Bundle outState) {
outState.putString(ENGINE_NAME_KEY, engine.customName);
- outState.putString(ENGINE_SERVER_KEY, engine.serverType.name());
+ outState.putString(ENGINE_SERVER_KEY, engine.type.name());
outState.putString(ENGINE_SERVER_URL_KEY, engine.customServerUrl);
outState.putString(ENGINE_VEHICLE_TYPE_KEY, engine.vehicleType.name());
outState.putString(ENGINE_CUSTOM_VEHICLE_KEY, engine.customVehicleKey);
@@ -508,7 +505,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
private void restoreState(Bundle savedState) {
engine.customName = savedState.getString(ENGINE_NAME_KEY);
- engine.serverType = ServerType.valueOf(savedState.getString(ENGINE_SERVER_KEY));
+ engine.type = EngineType.valueOf(savedState.getString(ENGINE_SERVER_KEY));
engine.customServerUrl = savedState.getString(ENGINE_SERVER_URL_KEY);
engine.vehicleType = VehicleType.valueOf(savedState.getString(ENGINE_VEHICLE_TYPE_KEY));
engine.customVehicleKey = savedState.getString(ENGINE_CUSTOM_VEHICLE_KEY);
@@ -519,16 +516,15 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
}
private void initState() {
- engine.serverType = ServerType.values()[0];
+ engine.type = EngineType.values()[0];
engine.vehicleType = VehicleType.values()[0];
selectedLocation = ExampleLocation.values()[0];
if (isEditingMode()) {
OnlineRoutingEngine editedEngine = helper.getEngineByKey(editedEngineKey);
if (editedEngine != null) {
- engine.customName = editedEngine.getParameter(EngineParameterType.CUSTOM_NAME);
- engine.serverType = editedEngine.getServerType();
- engine.customServerUrl = editedEngine.getParameter(EngineParameterType.CUSTOM_SERVER_URL);
+ engine.customName = editedEngine.getParameter(EngineParameter.CUSTOM_NAME);
+ engine.type = editedEngine.getType();
String vehicleKey = editedEngine.getVehicleKey();
if (vehicleKey != null) {
VehicleType vehicleType = VehicleType.getVehicleByKey(vehicleKey);
@@ -537,7 +533,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
}
engine.vehicleType = vehicleType;
}
- engine.apiKey = editedEngine.getParameter(EngineParameterType.API_KEY);
+ engine.apiKey = editedEngine.getParameter(EngineParameter.API_KEY);
}
}
}
@@ -568,8 +564,8 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
}
public static void showInstance(@NonNull FragmentActivity activity,
- @NonNull ApplicationMode appMode,
- String editedEngineKey) {
+ @NonNull ApplicationMode appMode,
+ String editedEngineKey) {
FragmentManager fm = activity.getSupportFragmentManager();
if (!fm.isStateSaved() && fm.findFragmentByTag(OnlineRoutingEngineFragment.TAG) == null) {
OnlineRoutingEngineFragment fragment = new OnlineRoutingEngineFragment();
@@ -583,7 +579,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
private static class OnlineRoutingEngineObject {
private String customName;
- private ServerType serverType;
+ private EngineType type;
private String customServerUrl;
private VehicleType vehicleType;
private String customVehicleKey;
@@ -596,15 +592,18 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
return vehicleType.getKey();
}
- public String getBaseUrl() {
- return customServerUrl != null ? customServerUrl : serverType.getBaseUrl();
- }
-
public String getName(Context ctx) {
if (customName != null) {
return customName;
}
- return OnlineRoutingEngine.getStandardName(ctx, serverType, getVehicleKey());
+ return OnlineRoutingEngine.getStandardName(ctx, type, getVehicleKey());
+ }
+
+ public String getBaseUrl() {
+ if (Algorithms.isEmpty(customServerUrl)) {
+ return type.getStandardUrl();
+ }
+ return customServerUrl;
}
}
}
diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java
index 54a5467bc1..b54746ddd6 100644
--- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java
+++ b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingHelper.java
@@ -6,18 +6,28 @@ import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import net.osmand.PlatformUtil;
+import net.osmand.data.LatLon;
+import net.osmand.osm.io.NetworkUtils;
import net.osmand.plus.OsmandApplication;
+import net.osmand.plus.Version;
+import net.osmand.plus.onlinerouting.OnlineRoutingEngine.EngineParameter;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.util.Algorithms;
+import net.osmand.util.GeoPolylineParserUtil;
import org.apache.commons.logging.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
import java.lang.reflect.Type;
+import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -27,8 +37,7 @@ public class OnlineRoutingHelper {
private OsmandApplication app;
private OsmandSettings settings;
- private List cachedEngines;
- private Map cachedEnginesMap;
+ private Map cachedEngines;
public OnlineRoutingHelper(OsmandApplication app) {
this.app = app;
@@ -38,23 +47,121 @@ public class OnlineRoutingHelper {
@NonNull
public List getEngines() {
- return cachedEngines;
+ return new ArrayList<>(cachedEngines.values());
}
public OnlineRoutingEngine getEngineByKey(String stringKey) {
- return cachedEnginesMap.get(stringKey);
+ return cachedEngines.get(stringKey);
+ }
+
+ public List calculateRouteOnline(@NonNull OnlineRoutingEngine engine,
+ @NonNull List path) throws IOException, JSONException {
+ String fullUrl = createFullUrl(engine, path);
+ String content = makeRequest(fullUrl);
+ return parseResponse(engine, content);
+ }
+
+ public String createFullUrl(OnlineRoutingEngine engine, List path) {
+ StringBuilder sb = new StringBuilder(engine.getBaseUrl());
+ String vehicle = engine.getVehicleKey();
+ String apiKey = engine.getParameter(EngineParameter.API_KEY);
+ switch (engine.getType()) {
+
+ case GRAPHHOPPER:
+ sb.append("?");
+ for (LatLon point : path) {
+ sb.append("point=")
+ .append(point.getLatitude())
+ .append(',')
+ .append(point.getLongitude())
+ .append('&');
+ }
+ sb.append("vehicle=").append(vehicle);
+
+ if (!Algorithms.isEmpty(apiKey)) {
+ sb.append('&').append("key=").append(apiKey);
+ }
+ break;
+
+ case OSRM:
+ sb.append(vehicle).append('/');
+ for (int i = 0; i < path.size(); i++) {
+ LatLon point = path.get(i);
+ sb.append(point.getLongitude()).append(',').append(point.getLatitude());
+ if (i < path.size() - 1) {
+ sb.append(';');
+ }
+ }
+ break;
+
+ case ORS:
+ if (path.size() > 1) {
+ sb.append("driving-car").append('?'); // todo only for testing
+ if (!Algorithms.isEmpty(apiKey)) {
+ sb.append("api_key=").append(apiKey);
+ }
+ LatLon start = path.get(0);
+ LatLon end = path.get(path.size() - 1);
+ sb.append('&').append("start=")
+ .append(start.getLatitude()).append(',').append(start.getLongitude());
+ sb.append('&').append("end=")
+ .append(end.getLatitude()).append(',').append(end.getLongitude());
+ }
+ break;
+
+ }
+ return sb.toString();
+ }
+
+ private List parseResponse(OnlineRoutingEngine engine, String content) throws JSONException {
+ JSONObject obj = new JSONObject(content);
+
+ switch (engine.getType()) {
+
+ case GRAPHHOPPER:
+ return GeoPolylineParserUtil.parse(
+ obj.getJSONArray("paths").getJSONObject(0).getString("points"),
+ GeoPolylineParserUtil.PRECISION_5);
+
+ case OSRM:
+ return GeoPolylineParserUtil.parse(
+ obj.getJSONArray("routes").getJSONObject(0).getString("geometry"),
+ GeoPolylineParserUtil.PRECISION_5);
+
+ case ORS:
+ JSONArray array = obj.getJSONArray("features").getJSONObject(0)
+ .getJSONObject("geometry").getJSONArray("coordinates");
+ List track = new ArrayList<>();
+ for (int i = 0; i < array.length(); i++) {
+ JSONArray point = array.getJSONArray(i);
+ double lat = Double.parseDouble(point.getString(0));
+ double lon = Double.parseDouble(point.getString(1));
+ track.add(new LatLon(lat, lon));
+ }
+ return track;
+ }
+ return new ArrayList<>();
+ }
+
+ private String makeRequest(String url) throws IOException {
+ URLConnection connection = NetworkUtils.getHttpURLConnection(url);
+ connection.setRequestProperty("User-Agent", Version.getFullVersion(app));
+ StringBuilder content = new StringBuilder();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+ String s;
+ while ((s = reader.readLine()) != null) {
+ content.append(s);
+ }
+ try {
+ reader.close();
+ } catch (IOException ignored) {
+ }
+ return content.toString();
}
public void saveEngine(@NonNull OnlineRoutingEngine engine) {
String stringKey = engine.getStringKey();
- OnlineRoutingEngine existedEngine = cachedEnginesMap.get(stringKey);
- if (existedEngine != null) {
- int index = cachedEngines.indexOf(existedEngine);
- cachedEngines.set(index, engine);
- } else {
- cachedEngines.add(engine);
- }
- cachedEnginesMap.put(stringKey, engine);
+ cachedEngines.put(stringKey, engine);
saveToSettings();
}
@@ -67,19 +174,18 @@ public class OnlineRoutingHelper {
public void deleteEngine(@NonNull OnlineRoutingEngine engine) {
String stringKey = engine.getStringKey();
- if (cachedEnginesMap.containsKey(stringKey)) {
- OnlineRoutingEngine existedEngine = cachedEnginesMap.remove(stringKey);
- cachedEngines.remove(existedEngine);
+ if (cachedEngines.containsKey(stringKey)) {
+ cachedEngines.remove(stringKey);
saveToSettings();
}
}
private void loadFromSettings() {
- cachedEngines = readFromSettings();
- cachedEnginesMap = new HashMap<>();
- for (OnlineRoutingEngine engine : cachedEngines) {
- cachedEnginesMap.put(engine.getStringKey(), engine);
+ Map cachedEngines = new LinkedHashMap<>();
+ for (OnlineRoutingEngine engine : readFromSettings()) {
+ cachedEngines.put(engine.getStringKey(), engine);
}
+ this.cachedEngines = cachedEngines;
}
@NonNull
@@ -101,7 +207,7 @@ public class OnlineRoutingHelper {
if (!Algorithms.isEmpty(cachedEngines)) {
try {
JSONObject json = new JSONObject();
- writeToJson(json, cachedEngines);
+ writeToJson(json, getEngines());
settings.ONLINE_ROUTING_ENGINES.set(json.toString());
} catch (JSONException e) {
LOG.debug("Error when writing engines to JSON ", e);
@@ -123,10 +229,10 @@ public class OnlineRoutingHelper {
JSONObject object = itemsJson.getJSONObject(i);
String key = object.getString("key");
String vehicleKey = object.getString("vehicle");
- ServerType serverType = ServerType.valueOf(object.getString("serverType"));
+ EngineType engineType = EngineType.valueOf(object.getString("type"));
String paramsString = object.getString("params");
HashMap params = gson.fromJson(paramsString, type);
- engines.add(new OnlineRoutingEngine(key, serverType, vehicleKey, params));
+ engines.add(new OnlineRoutingEngine(key, engineType, vehicleKey, params));
}
}
@@ -138,7 +244,7 @@ public class OnlineRoutingHelper {
for (OnlineRoutingEngine engine : engines) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("key", engine.getStringKey());
- jsonObject.put("serverType", engine.getServerType().name());
+ jsonObject.put("type", engine.getType().name());
jsonObject.put("vehicle", engine.getVehicleKey());
jsonObject.put("params", gson.toJson(engine.getParams(), type));
jsonArray.put(jsonObject);
diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/ServerType.java b/OsmAnd/src/net/osmand/plus/onlinerouting/ServerType.java
deleted file mode 100644
index 7eb30798d5..0000000000
--- a/OsmAnd/src/net/osmand/plus/onlinerouting/ServerType.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package net.osmand.plus.onlinerouting;
-
-public enum ServerType {
- GRAPHHOPER("Graphhoper", "https://graphhopper.com/api/1/route"),
- OSRM("OSRM", "https://zlzk.biz/route/v1/");
-
- ServerType(String title, String baseUrl) {
- this.title = title;
- this.baseUrl = baseUrl;
- }
-
- private String title;
- private String baseUrl;
-
- public String getTitle() {
- return title;
- }
-
- public String getBaseUrl() {
- return baseUrl;
- }
-}
diff --git a/OsmAnd/src/net/osmand/plus/poi/PoiUIFilter.java b/OsmAnd/src/net/osmand/plus/poi/PoiUIFilter.java
index 1d3449640f..0d837f560a 100644
--- a/OsmAnd/src/net/osmand/plus/poi/PoiUIFilter.java
+++ b/OsmAnd/src/net/osmand/plus/poi/PoiUIFilter.java
@@ -352,11 +352,11 @@ public class PoiUIFilter implements SearchPoiTypeFilter, Comparable
}
};
}
- StringBuilder nmFilter = new StringBuilder();
String[] items = filter.split(" ");
boolean allTime = false;
boolean open = false;
List poiAdditionalsFilter = null;
+ List unknownFilters = null;
for (String s : items) {
s = s.trim();
if (!Algorithms.isEmpty(s)) {
@@ -373,110 +373,179 @@ public class PoiUIFilter implements SearchPoiTypeFilter, Comparable
poiAdditionalsFilter.add(pt);
}
} else {
- nmFilter.append(s).append(" ");
+ if (unknownFilters == null) {
+ unknownFilters = new ArrayList<>();
+ }
+ unknownFilters.add(s);
}
}
}
- return getNameFilterInternal(nmFilter, allTime, open, poiAdditionalsFilter);
+ return getNameFilterInternal(unknownFilters, allTime, open, poiAdditionalsFilter);
}
- private AmenityNameFilter getNameFilterInternal(StringBuilder nmFilter,
- final boolean allTime, final boolean open, final List poiAdditionals) {
- final CollatorStringMatcher sm = nmFilter.length() > 0 ?
- new CollatorStringMatcher(nmFilter.toString().trim(), StringMatcherMode.CHECK_CONTAINS) : null;
+ private AmenityNameFilter getNameFilterInternal(
+ final List unknownFilters, final boolean shouldBeAllTime,
+ final boolean shouldBeOpened, final List selectedFilters
+ ) {
return new AmenityNameFilter() {
@Override
- public boolean accept(Amenity a) {
- if (sm != null) {
- List names = OsmAndFormatter.getPoiStringsWithoutType(a,
- app.getSettings().MAP_PREFERRED_LOCALE.get(), app.getSettings().MAP_TRANSLITERATE_NAMES.get());
- boolean match = false;
- for (String name : names) {
- if (sm.matches(name)) {
- match = true;
- break;
- }
- }
- if (!match) {
+ public boolean accept(Amenity amenity) {
+ if (shouldBeAllTime) {
+ if (!"24/7".equalsIgnoreCase(amenity.getOpeningHours()) &&
+ !"Mo-Su 00:00-24:00".equalsIgnoreCase(amenity.getOpeningHours())) {
return false;
}
}
- if (poiAdditionals != null) {
- Map textPoiAdditionalsMap = new HashMap<>();
- Map> poiAdditionalCategoriesMap = new HashMap<>();
- for (PoiType pt : poiAdditionals) {
- String category = pt.getPoiAdditionalCategory();
- List types = poiAdditionalCategoriesMap.get(category);
- if (types == null) {
- types = new ArrayList<>();
- poiAdditionalCategoriesMap.put(category, types);
- }
- types.add(pt);
- String osmTag = pt.getOsmTag();
- if (osmTag.length() < pt.getKeyName().length()) {
- PoiType textPoiType = poiTypes.getTextPoiAdditionalByKey(osmTag);
- if (textPoiType != null) {
- textPoiAdditionalsMap.put(pt, textPoiType);
- }
- }
- }
- for (List types : poiAdditionalCategoriesMap.values()) {
- boolean acceptedAnyInCategory = false;
- for (PoiType p : types) {
- String inf = a.getAdditionalInfo(p.getKeyName());
- if (inf != null) {
- acceptedAnyInCategory = true;
- break;
- } else {
- PoiType textPoiType = textPoiAdditionalsMap.get(p);
- if (textPoiType != null) {
- inf = a.getAdditionalInfo(textPoiType.getKeyName());
- if (!Algorithms.isEmpty(inf)) {
- String[] items = inf.split(";");
- String val = p.getOsmValue().trim().toLowerCase();
- for (String item : items) {
- if (item.trim().toLowerCase().equals(val)) {
- acceptedAnyInCategory = true;
- break;
- }
- }
- if (acceptedAnyInCategory) {
- break;
- }
- }
- }
- }
- }
- if (!acceptedAnyInCategory) {
- return false;
- }
- }
+ if (shouldBeOpened && !isOpened(amenity)) {
+ return false;
}
- if (allTime) {
- if (!"24/7".equalsIgnoreCase(a.getOpeningHours()) && !"Mo-Su 00:00-24:00".equalsIgnoreCase(a.getOpeningHours())) {
- return false;
- }
+
+ String nameFilter = extractNameFilter(amenity, unknownFilters);
+ if (!matchesAnyAmenityName(amenity, nameFilter)) {
+ return false;
}
- if (open) {
- OpeningHours rs = OpeningHoursParser.parseOpenedHours(a.getOpeningHours());
- if (rs != null) {
- Calendar inst = Calendar.getInstance();
- inst.setTimeInMillis(System.currentTimeMillis());
- boolean work = rs.isOpenedForTime(inst);
- if (!work) {
- return false;
- }
- } else {
- return false;
- }
+
+ if (!acceptedAnyFilterOfEachCategory(amenity, selectedFilters)) {
+ return false;
}
+
return true;
}
};
}
+ private boolean isOpened(Amenity amenity) {
+ OpeningHours openedHours = OpeningHoursParser.parseOpenedHours(amenity.getOpeningHours());
+ if (openedHours == null) {
+ return false;
+ }
+
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(System.currentTimeMillis());
+
+ return openedHours.isOpenedForTime(calendar);
+ }
+
+ private String extractNameFilter(Amenity amenity, List unknownFilters) {
+ if (unknownFilters == null) {
+ return "";
+ }
+
+ StringBuilder nameFilter = new StringBuilder();
+ for (String filter : unknownFilters) {
+ String formattedFilter = filter.replace(':', '_').toLowerCase();
+ if (amenity.getAdditionalInfo(formattedFilter) == null) {
+ nameFilter.append(filter).append(" ");
+ }
+ }
+
+ return nameFilter.toString();
+ }
+
+ private boolean matchesAnyAmenityName(Amenity amenity, String nameFilter) {
+ if (nameFilter.length() == 0) {
+ return true;
+ }
+
+ final CollatorStringMatcher sm =
+ new CollatorStringMatcher(nameFilter.trim(), StringMatcherMode.CHECK_CONTAINS);
+
+ List names = OsmAndFormatter.getPoiStringsWithoutType(
+ amenity, app.getSettings().MAP_PREFERRED_LOCALE.get(),
+ app.getSettings().MAP_TRANSLITERATE_NAMES.get());
+ for (String name : names) {
+ if (sm.matches(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean acceptedAnyFilterOfEachCategory(Amenity amenity, List selectedFilters) {
+ if (selectedFilters == null) {
+ return true;
+ }
+
+ Map> filterCategories = new HashMap<>();
+ Map textFilters = new HashMap<>();
+
+ fillFilterCategories(selectedFilters, filterCategories, textFilters);
+
+ for (List category : filterCategories.values()) {
+ if (!acceptedAnyFilterOfCategory(amenity, category, textFilters)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void fillFilterCategories(
+ List selectedFilters,
+ Map> filterCategories, Map textFilters
+ ) {
+ for (PoiType filter : selectedFilters) {
+ String category = filter.getPoiAdditionalCategory();
+ List filtersOfCategory = filterCategories.get(category);
+ if (filtersOfCategory == null) {
+ filtersOfCategory = new ArrayList<>();
+ filterCategories.put(category, filtersOfCategory);
+ }
+ filtersOfCategory.add(filter);
+
+ String osmTag = filter.getOsmTag();
+ if (osmTag.length() < filter.getKeyName().length()) {
+ PoiType textFilter = poiTypes.getTextPoiAdditionalByKey(osmTag);
+ if (textFilter != null) {
+ textFilters.put(filter, textFilter);
+ }
+ }
+ }
+ }
+
+ private boolean acceptedAnyFilterOfCategory(
+ Amenity amenity, List category, Map textFilters) {
+ for (PoiType filter : category) {
+ if (acceptedFilter(amenity, filter, textFilters)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private boolean acceptedFilter(
+ Amenity amenity, PoiType filter, Map textFilterCategories
+ ) {
+ String filterValue = amenity.getAdditionalInfo(filter.getKeyName());
+
+ if (filterValue != null) {
+ return true;
+ }
+
+ PoiType textPoiType = textFilterCategories.get(filter);
+ if (textPoiType == null) {
+ return false;
+ }
+
+ filterValue = amenity.getAdditionalInfo(textPoiType.getKeyName());
+ if (Algorithms.isEmpty(filterValue)) {
+ return false;
+ }
+
+ String[] items = filterValue.split(";");
+ String val = filter.getOsmValue().trim().toLowerCase();
+ for (String item : items) {
+ if (item.trim().toLowerCase().equals(val)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
public String getNameToken24H() {
return app.getString(R.string.shared_string_is_open_24_7).replace(' ', '_').toLowerCase();
}
diff --git a/OsmAnd/src/net/osmand/plus/profiles/ProfileDataUtils.java b/OsmAnd/src/net/osmand/plus/profiles/ProfileDataUtils.java
index f769f69bdb..28967ba2f3 100644
--- a/OsmAnd/src/net/osmand/plus/profiles/ProfileDataUtils.java
+++ b/OsmAnd/src/net/osmand/plus/profiles/ProfileDataUtils.java
@@ -22,6 +22,7 @@ import java.util.Map;
public class ProfileDataUtils {
public static final String OSMAND_NAVIGATION = "osmand_navigation";
+ public static final String ONLINE_NAVIGATION = "online_navigation";
public static List getDataObjects(OsmandApplication app,
List appModes) {
@@ -48,9 +49,9 @@ public class ProfileDataUtils {
return description;
}
- public static List getSortedRoutingProfiles(OsmandApplication app) {
- List result = new ArrayList<>();
- Map> routingProfilesByFileNames = getRoutingProfilesByFileNames(app);
+ public static List getSortedRoutingProfiles(OsmandApplication app) {
+ List result = new ArrayList<>();
+ Map> routingProfilesByFileNames = getRoutingProfilesByFileNames(app);
List fileNames = new ArrayList<>(routingProfilesByFileNames.keySet());
Collections.sort(fileNames, new Comparator() {
@Override
@@ -59,7 +60,7 @@ public class ProfileDataUtils {
}
});
for (String fileName : fileNames) {
- List routingProfilesFromFile = routingProfilesByFileNames.get(fileName);
+ List routingProfilesFromFile = routingProfilesByFileNames.get(fileName);
if (routingProfilesFromFile != null) {
Collections.sort(routingProfilesFromFile);
result.addAll(routingProfilesFromFile);
@@ -77,14 +78,20 @@ public class ProfileDataUtils {
return objects;
}
- public static Map> getRoutingProfilesByFileNames(OsmandApplication app) {
- Map> result = new HashMap<>();
- for (final RoutingProfileDataObject profile : getRoutingProfiles(app).values()) {
- String fileName = profile.getFileName() != null ? profile.getFileName() : OSMAND_NAVIGATION;
+ public static Map> getRoutingProfilesByFileNames(OsmandApplication app) {
+ Map> result = new HashMap<>();
+ for (final ProfileDataObject profile : getRoutingProfiles(app).values()) {
+ String fileName = null;
+ if (profile instanceof RoutingProfileDataObject) {
+ fileName = ((RoutingProfileDataObject) profile).getFileName();
+ } else if (profile instanceof OnlineRoutingEngineDataObject) {
+ fileName = ONLINE_NAVIGATION;
+ }
+ fileName = fileName != null ? fileName : OSMAND_NAVIGATION;
if (result.containsKey(fileName)) {
result.get(fileName).add(profile);
} else {
- result.put(fileName, new ArrayList() {
+ result.put(fileName, new ArrayList() {
{ add(profile); }
});
}
@@ -92,8 +99,8 @@ public class ProfileDataUtils {
return result;
}
- public static Map getRoutingProfiles(OsmandApplication context) {
- Map profilesObjects = new HashMap<>();
+ public static Map getRoutingProfiles(OsmandApplication context) {
+ Map profilesObjects = new HashMap<>();
profilesObjects.put(RoutingProfilesResources.STRAIGHT_LINE_MODE.name(), new RoutingProfileDataObject(
RoutingProfilesResources.STRAIGHT_LINE_MODE.name(),
context.getString(RoutingProfilesResources.STRAIGHT_LINE_MODE.getStringRes()),
@@ -119,11 +126,14 @@ public class ProfileDataUtils {
for (RoutingConfiguration.Builder builder : context.getAllRoutingConfigs()) {
collectRoutingProfilesFromConfig(context, builder, profilesObjects, disabledRouterNames);
}
+ for (OnlineRoutingEngineDataObject onlineEngine : getOnlineRoutingProfiles(context)) {
+ profilesObjects.put(onlineEngine.getStringKey(), onlineEngine);
+ }
return profilesObjects;
}
private static void collectRoutingProfilesFromConfig(OsmandApplication app, RoutingConfiguration.Builder builder,
- Map profilesObjects, List disabledRouterNames) {
+ Map profilesObjects, List disabledRouterNames) {
for (Map.Entry entry : builder.getAllRouters().entrySet()) {
String routerKey = entry.getKey();
GeneralRouter router = entry.getValue();
diff --git a/OsmAnd/src/net/osmand/plus/profiles/SelectProfileBottomSheet.java b/OsmAnd/src/net/osmand/plus/profiles/SelectProfileBottomSheet.java
index df2bd8b879..98ca4771cc 100644
--- a/OsmAnd/src/net/osmand/plus/profiles/SelectProfileBottomSheet.java
+++ b/OsmAnd/src/net/osmand/plus/profiles/SelectProfileBottomSheet.java
@@ -4,6 +4,7 @@ import android.app.Activity;
import android.content.Context;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.Spanned;
@@ -58,7 +59,7 @@ public class SelectProfileBottomSheet extends BasePreferenceBottomSheet {
public final static String PROFILE_KEY_ARG = "profile_key_arg";
public final static String USE_LAST_PROFILE_ARG = "use_last_profile_arg";
- public final static String IS_PROFILE_IMPORTED_ARG = "is_profile_imported_arg";
+ public final static String PROFILES_LIST_UPDATED_ARG = "is_profiles_list_updated";
private DialogMode dialogMode;
private final List profiles = new ArrayList<>();
@@ -130,7 +131,7 @@ public class SelectProfileBottomSheet extends BasePreferenceBottomSheet {
}
Bundle args = new Bundle();
args.putString(PROFILE_KEY_ARG, item.getName());
- args.putBoolean(IS_PROFILE_IMPORTED_ARG, true);
+ args.putBoolean(PROFILES_LIST_UPDATED_ARG, true);
listener.onSelectedType(args);
dismiss();
break;
@@ -234,9 +235,10 @@ public class SelectProfileBottomSheet extends BasePreferenceBottomSheet {
int activeColorResId = nightMode ? R.color.active_color_primary_dark : R.color.active_color_primary_light;
int iconDefaultColorResId = nightMode ? R.color.icon_color_default_dark : R.color.icon_color_default_light;
+ final boolean onlineRoutingProfile = profile instanceof OnlineRoutingEngineDataObject;
View itemView = UiUtilities.getInflater(getContext(), nightMode).inflate(
- profile instanceof OnlineRoutingEngineDataObject ?
+ onlineRoutingProfile ?
R.layout.bottom_sheet_item_with_descr_radio_and_icon_btn :
R.layout.bottom_sheet_item_with_descr_and_radio_btn, null);
TextView tvTitle = itemView.findViewById(R.id.title);
@@ -262,28 +264,52 @@ public class SelectProfileBottomSheet extends BasePreferenceBottomSheet {
UiUtilities.setupCompoundButton(compoundButton, nightMode, UiUtilities.CompoundButtonType.GLOBAL);
bottomDivider.setVisibility(showBottomDivider ? View.VISIBLE : View.INVISIBLE);
- items.add(new BaseBottomSheetItem.Builder()
- .setCustomView(itemView)
- .setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View view) {
- Bundle args = new Bundle();
- args.putString(PROFILE_KEY_ARG, profile.getStringKey());
- Fragment target = getTargetFragment();
- if (target instanceof OnSelectProfileCallback) {
- if (profile instanceof OnlineRoutingEngineDataObject) {
- if (getActivity() != null) {
- OnlineRoutingEngineFragment.showInstance(getActivity(), getAppMode(), profile.getStringKey());
- }
- dismiss();
- } else {
- ((OnSelectProfileCallback) target).onProfileSelected(args);
- }
- }
- dismiss();
+ BaseBottomSheetItem.Builder builder =
+ new BaseBottomSheetItem.Builder().setCustomView(itemView);
+
+ OnClickListener listener = new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Bundle args = new Bundle();
+ args.putString(PROFILE_KEY_ARG, profile.getStringKey());
+ args.putBoolean(PROFILES_LIST_UPDATED_ARG, onlineRoutingProfile);
+ Fragment target = getTargetFragment();
+ if (target instanceof OnSelectProfileCallback) {
+ ((OnSelectProfileCallback) target).onProfileSelected(args);
+ }
+ dismiss();
+ }
+ };
+
+ if (onlineRoutingProfile) {
+ View basePart = itemView.findViewById(R.id.basic_item_body);
+ View endBtn = itemView.findViewById(R.id.end_button);
+ ImageView ivEndBtnIcon = itemView.findViewById(R.id.end_button_icon);
+
+ Drawable drawable = getIcon(R.drawable.ic_action_settings,
+ nightMode ?
+ R.color.route_info_control_icon_color_dark :
+ R.color.route_info_control_icon_color_light);
+ if (Build.VERSION.SDK_INT >= 21) {
+ Drawable activeDrawable = getIcon(R.drawable.ic_action_settings, activeColorResId);
+ drawable = AndroidUtils.createPressedStateListDrawable(drawable, activeDrawable);
+ }
+ ivEndBtnIcon.setImageDrawable(drawable);
+
+ basePart.setOnClickListener(listener);
+ endBtn.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (getActivity() != null) {
+ OnlineRoutingEngineFragment.showInstance(getActivity(), getAppMode(), profile.getStringKey());
}
- })
- .create());
+ dismiss();
+ }
+ });
+ } else {
+ builder.setOnClickListener(listener);
+ }
+ items.add(builder.create());
}
private void addCheckableItem(int titleId,
@@ -363,7 +389,6 @@ public class SelectProfileBottomSheet extends BasePreferenceBottomSheet {
case NAVIGATION_PROFILE:
profiles.addAll(ProfileDataUtils.getSortedRoutingProfiles(app));
- profiles.addAll(ProfileDataUtils.getOnlineRoutingProfiles(app));
break;
case DEFAULT_PROFILE:
diff --git a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java
index 37bb29d148..89c17f1c2b 100644
--- a/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java
+++ b/OsmAnd/src/net/osmand/plus/routing/RouteProvider.java
@@ -22,6 +22,8 @@ import net.osmand.data.LocationPoint;
import net.osmand.data.WptLocationPoint;
import net.osmand.osm.io.NetworkUtils;
import net.osmand.plus.OsmandApplication;
+import net.osmand.plus.onlinerouting.OnlineRoutingEngine;
+import net.osmand.plus.onlinerouting.OnlineRoutingHelper;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.settings.backend.CommonPreference;
import net.osmand.plus.R;
@@ -91,7 +93,8 @@ public class RouteProvider {
OSMAND("OsmAnd (offline)"),
BROUTER("BRouter (offline)"),
STRAIGHT("Straight line"),
- DIRECT_TO("Direct To");
+ DIRECT_TO("Direct To"),
+ ONLINE("Online engine");
private final String name;
@@ -363,10 +366,8 @@ public class RouteProvider {
res = findVectorMapsRoute(params, calcGPXRoute);
} else if (params.mode.getRouteService() == RouteService.BROUTER) {
res = findBROUTERRoute(params);
-// } else if (params.type == RouteService.ORS) {
-// res = findORSRoute(params);
-// } else if (params.type == RouteService.OSRM) {
-// res = findOSRMRoute(params);
+ } else if (params.mode.getRouteService() == RouteService.ONLINE) {
+ res = findOnlineRoute(params);
} else if (params.mode.getRouteService() == RouteService.STRAIGHT ||
params.mode.getRouteService() == RouteService.DIRECT_TO) {
res = findStraightRoute(params);
@@ -383,6 +384,8 @@ public class RouteProvider {
log.error("Failed to find route ", e); //$NON-NLS-1$
} catch (SAXException e) {
log.error("Failed to find route ", e); //$NON-NLS-1$
+ } catch (JSONException e) {
+ log.error("Failed to find route ", e); //$NON-NLS-1$
}
}
return new RouteCalculationResult(null);
@@ -1204,64 +1207,33 @@ public class RouteProvider {
return exporter.exportRoute();
}
- private void appendOSRMLoc(StringBuilder uri, LatLon il) {
- uri.append(";").append(il.getLongitude());
- uri.append(",").append(il.getLatitude());
- }
-
- protected RouteCalculationResult findOSRMRoute(RouteCalculationParams params)
- throws MalformedURLException, IOException, JSONException {
- // http://router.project-osrm.org/route/v1/driving/4.83,52.28;4.95,52.28
- List res = new ArrayList();
- StringBuilder uri = new StringBuilder();
- // possibly hide that API key because it is privacy of osmand
- // A6421860EBB04234AB5EF2D049F2CD8F key is compromised
- String scheme = "";
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
- scheme = "https";
- } else {
- scheme = "http";
- }
- uri.append(scheme + "://router.project-osrm.org/route/v1/driving/"); //$NON-NLS-1$
- uri.append(String.valueOf(params.start.getLongitude()));
- uri.append(",").append(String.valueOf(params.start.getLatitude()));
- if(params.intermediates != null && params.intermediates.size() > 0) {
- for(LatLon il : params.intermediates) {
- appendOSRMLoc(uri, il);
+ private RouteCalculationResult findOnlineRoute(RouteCalculationParams params) throws IOException, JSONException {
+ OnlineRoutingHelper helper = params.ctx.getOnlineRoutingHelper();
+ String stringKey = params.mode.getRoutingProfile();
+ List route = helper.calculateRouteOnline(helper.getEngineByKey(stringKey), getFullPathFromParams(params));
+ if (!route.isEmpty()) {
+ List res = new ArrayList<>();
+ for (LatLon pt : route) {
+ WptPt wpt = new WptPt();
+ wpt.lat = pt.getLatitude();
+ wpt.lon = pt.getLongitude();
+ res.add(createLocation(wpt));
}
- }
- appendOSRMLoc(uri, params.end);
-// to get more waypoints, add overview=full option
-// uri.append("?overview=full")
-
- log.info("URL route " + uri);
-
- URLConnection connection = NetworkUtils.getHttpURLConnection(uri.toString());
- connection.setRequestProperty("User-Agent", Version.getFullVersion(params.ctx));
- StringBuilder content = new StringBuilder();
- BufferedReader rs = new BufferedReader(new InputStreamReader(connection.getInputStream()));
- String s;
- while((s = rs.readLine()) != null) {
- content.append(s);
- }
- JSONObject obj = new JSONObject(content.toString());
- try {
- rs.close();
- } catch(IOException e){
- }
- List route = GeoPolylineParserUtil.parse(obj.getJSONArray("routes").getJSONObject(0).getString("geometry"),
- GeoPolylineParserUtil.PRECISION_5);
- if (route.isEmpty()) {
+ params.intermediates = null;
+ return new RouteCalculationResult(res, null, params, null, true);
+ } else {
return new RouteCalculationResult("Route is empty");
}
- for (LatLon pt : route) {
- WptPt wpt = new WptPt();
- wpt.lat = pt.getLatitude();
- wpt.lon = pt.getLongitude();
- res.add(createLocation(wpt));
+ }
+
+ private static List getFullPathFromParams(RouteCalculationParams params) {
+ List points = new ArrayList<>();
+ points.add(new LatLon(params.start.getLatitude(), params.start.getLongitude()));
+ if (Algorithms.isEmpty(params.intermediates)) {
+ points.addAll(params.intermediates);
}
- params.intermediates = null;
- return new RouteCalculationResult(res, null, params, null, true);
+ points.add(params.end);
+ return points;
}
protected RouteCalculationResult findBROUTERRoute(RouteCalculationParams params) throws MalformedURLException,
diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/backup/OnlineRoutingSettingsItem.java b/OsmAnd/src/net/osmand/plus/settings/backend/backup/OnlineRoutingSettingsItem.java
index e5ae306cf0..779a97d1df 100644
--- a/OsmAnd/src/net/osmand/plus/settings/backend/backup/OnlineRoutingSettingsItem.java
+++ b/OsmAnd/src/net/osmand/plus/settings/backend/backup/OnlineRoutingSettingsItem.java
@@ -8,7 +8,7 @@ import androidx.annotation.Nullable;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.onlinerouting.OnlineRoutingEngine;
-import net.osmand.plus.onlinerouting.OnlineRoutingEngine.EngineParameterType;
+import net.osmand.plus.onlinerouting.OnlineRoutingEngine.EngineParameter;
import net.osmand.plus.onlinerouting.OnlineRoutingHelper;
import org.json.JSONException;
@@ -93,8 +93,8 @@ public class OnlineRoutingSettingsItem extends CollectionSettingsItem routingProfileDataObjects;
+ private Map routingProfileDataObjects;
private Preference navigationType;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- routingProfileDataObjects = ProfileDataUtils.getRoutingProfiles(app);
+ updateRoutingProfilesDataObjects();
setupOnBackPressedCallback();
}
@@ -90,7 +92,7 @@ public class NavigationFragment extends BaseSettingsFragment implements OnSelect
private void setupNavigationTypePref() {
String routingProfileKey = getSelectedAppMode().getRoutingProfile();
if (!Algorithms.isEmpty(routingProfileKey)) {
- RoutingProfileDataObject routingProfileDataObject = routingProfileDataObjects.get(routingProfileKey);
+ ProfileDataObject routingProfileDataObject = routingProfileDataObjects.get(routingProfileKey);
if (routingProfileDataObject != null) {
navigationType.setSummary(routingProfileDataObject.getName());
navigationType.setIcon(getActiveIcon(routingProfileDataObject.getIconRes()));
@@ -132,12 +134,16 @@ public class NavigationFragment extends BaseSettingsFragment implements OnSelect
return false;
}
+ private void updateRoutingProfilesDataObjects() {
+ routingProfileDataObjects = ProfileDataUtils.getRoutingProfiles(app);
+ }
+
void updateRoutingProfile(String profileKey) {
- RoutingProfileDataObject selectedRoutingProfileDataObject = routingProfileDataObjects.get(profileKey);
+ ProfileDataObject selectedRoutingProfileDataObject = routingProfileDataObjects.get(profileKey);
if (profileKey == null || selectedRoutingProfileDataObject == null) {
return;
}
- for (Map.Entry rp : routingProfileDataObjects.entrySet()) {
+ for (Map.Entry rp : routingProfileDataObjects.entrySet()) {
boolean selected = profileKey.equals(rp.getKey());
rp.getValue().setSelected(selected);
}
@@ -152,6 +158,8 @@ public class NavigationFragment extends BaseSettingsFragment implements OnSelect
routeService = RouteProvider.RouteService.DIRECT_TO;
} else if (profileKey.equals(RoutingProfilesResources.BROUTER_MODE.name())) {
routeService = RouteProvider.RouteService.BROUTER;
+ } else if (profileKey.startsWith(ONLINE_ROUTING_ENGINE_PREFIX)) {
+ routeService = RouteService.ONLINE;
} else {
routeService = RouteProvider.RouteService.OSMAND;
}
@@ -174,8 +182,8 @@ public class NavigationFragment extends BaseSettingsFragment implements OnSelect
@Override
public void onProfileSelected(Bundle args) {
- if (args.getBoolean(IS_PROFILE_IMPORTED_ARG)) {
- routingProfileDataObjects = ProfileDataUtils.getRoutingProfiles(app);
+ if (args.getBoolean(PROFILES_LIST_UPDATED_ARG)) {
+ updateRoutingProfilesDataObjects();
}
updateRoutingProfile(args.getString(PROFILE_KEY_ARG));
}
diff --git a/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java b/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java
index 7a42818745..7e1277ca18 100644
--- a/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java
+++ b/OsmAnd/src/net/osmand/plus/settings/fragments/ProfileAppearanceFragment.java
@@ -66,7 +66,7 @@ import java.util.ArrayList;
import java.util.Collections;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.DRAWER_SETTINGS_ID;
-import static net.osmand.plus.profiles.SelectProfileBottomSheet.IS_PROFILE_IMPORTED_ARG;
+import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILES_LIST_UPDATED_ARG;
import static net.osmand.plus.profiles.SelectProfileBottomSheet.PROFILE_KEY_ARG;
public class ProfileAppearanceFragment extends BaseSettingsFragment implements OnSelectProfileCallback {
@@ -934,7 +934,7 @@ public class ProfileAppearanceFragment extends BaseSettingsFragment implements O
@Override
public void onProfileSelected(Bundle args) {
String profileKey = args.getString(PROFILE_KEY_ARG);
- boolean imported = args.getBoolean(IS_PROFILE_IMPORTED_ARG);
+ boolean imported = args.getBoolean(PROFILES_LIST_UPDATED_ARG);
updateParentProfile(profileKey, imported);
}
diff --git a/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelObfHelper.java b/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelObfHelper.java
index 484fc2a34d..983663f3d1 100644
--- a/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelObfHelper.java
+++ b/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelObfHelper.java
@@ -574,7 +574,7 @@ public class TravelObfHelper implements TravelHelper {
@Nullable
@Override
public TravelArticle getArticleByTitle(@NonNull final String title, @NonNull LatLon latLon, @NonNull final String lang) {
- QuadRect rect = MapUtils.calculateLatLonBbox(latLon.getLatitude(), latLon.getLongitude(), ARTICLE_SEARCH_RADIUS);
+ QuadRect rect = latLon != null ? MapUtils.calculateLatLonBbox(latLon.getLatitude(), latLon.getLongitude(), ARTICLE_SEARCH_RADIUS) : new QuadRect();
return getArticleByTitle(title, rect, lang);
}
@@ -582,7 +582,7 @@ public class TravelObfHelper implements TravelHelper {
@Override
public TravelArticle getArticleByTitle(@NonNull final String title, @NonNull QuadRect rect, @NonNull final String lang) {
TravelArticle article = null;
- List amenities = null;
+ final List amenities = new ArrayList<>();
int x = 0;
int y = 0;
int left = 0;
@@ -600,9 +600,25 @@ public class TravelObfHelper implements TravelHelper {
for (BinaryMapIndexReader reader : getReaders()) {
try {
SearchRequest req = BinaryMapIndexReader.buildSearchPoiRequest(
- x, y, title, left, right, top, bottom, getSearchFilter(false), null, null);
- req.setLimit(1);
- amenities = reader.searchPoiByName(req);
+ x, y, title, left, right, top, bottom, getSearchFilter(false),
+ new ResultMatcher() {
+ boolean done = false;
+
+ @Override
+ public boolean publish(Amenity amenity) {
+ if (Algorithms.stringsEqual(title, Algorithms.emptyIfNull(amenity.getName(lang)))) {
+ amenities.add(amenity);
+ done = true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return done;
+ }
+ }, null);
+ reader.searchPoiByName(req);
} catch (IOException e) {
LOG.error(e.getMessage());
}
diff --git a/build.gradle b/build.gradle
index 2789ee2902..b2c1082c91 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,5 @@
buildscript {
- ext.kotlin_version = '1.4.10'
+ ext.kotlin_version = '1.4.21'
repositories {
google()
mavenCentral()