This commit is contained in:
unknown 2014-05-22 11:10:22 +03:00
commit f254dedb18
23 changed files with 1156 additions and 262 deletions

View file

@ -559,7 +559,7 @@
<string name="search_history_street">Rue :\n{0}\n{1}</string> <string name="search_history_street">Rue :\n{0}\n{1}</string>
<string name="search_history_int_streets">Intersection :\n{0} x {1} dans {2}</string> <string name="search_history_int_streets">Intersection :\n{0} x {1} dans {2}</string>
<string name="search_history_building">Bâtiment :\n{0} {1}\n{2}</string> <string name="search_history_building">Bâtiment :\n{0} {1}\n{2}</string>
<string name="favorite">Favori</string> <string name="favorite">Favori </string>
<string name="clear_all">Effacer tout</string> <string name="clear_all">Effacer tout</string>
<string name="history">Historique</string> <string name="history">Historique</string>
<string name="uploading_data">Envoi des données…</string> <string name="uploading_data">Envoi des données…</string>
@ -601,7 +601,7 @@
<string name="opening_changeset">Ouverture des modifications…</string> <string name="opening_changeset">Ouverture des modifications…</string>
<string name="closing_changeset">Fermeture des modifications…</string> <string name="closing_changeset">Fermeture des modifications…</string>
<string name="commiting_node">Envoi des nœuds…</string> <string name="commiting_node">Envoi des nœuds…</string>
<string name="loading_poi_obj">Chargement des Points d\'Intérêts…</string> <string name="loading_poi_obj">Chargement des Points d\'intérêts…</string>
<string name="auth_failed">Autorisation refusée</string> <string name="auth_failed">Autorisation refusée</string>
<string name="failed_op">Échec</string> <string name="failed_op">Échec</string>
<string name="converting_names">Convertir les noms en anglais…</string> <string name="converting_names">Convertir les noms en anglais…</string>
@ -909,14 +909,14 @@
<string name="gpxup_private">Privé</string> <string name="gpxup_private">Privé</string>
<string name="osmand_parking_event">Récupérer votre véhicule du parking</string> <string name="osmand_parking_event">Récupérer votre véhicule du parking</string>
<string name="osmand_parking_warning">Avertissement</string> <string name="osmand_parking_warning">Avertissement</string>
<string name="osmand_parking_warning_text">Une notification pour récupérer votre véhicule a été ajoutée dans votre agenda. Elle y restera jusqu\'à ce que vous le supprimiez manuellement.</string> <string name="osmand_parking_warning_text">Une notification pour récupérer votre véhicule a été ajoutée dans votre agenda. Elle y restera jusqu\'à ce que vous la supprimiez manuellement.</string>
<string name="osmand_parking_time_limit_title">Donner un temps limite de stationnement</string> <string name="osmand_parking_time_limit_title">Donner un temps limite de stationnement</string>
<string name="osmand_parking_delete_confirm">Voulez-vous supprimer l\'emplacement de stationnement du véhicule ?</string> <string name="osmand_parking_delete_confirm">Voulez-vous supprimer l\'emplacement de stationnement du véhicule ?</string>
<string name="osmand_parking_delete">Supprimer un emplacement de stationnement</string> <string name="osmand_parking_delete">Supprimer un emplacement de stationnement</string>
<string name="osmand_parking_choose_type">Choisir le type de stationnement</string> <string name="osmand_parking_choose_type">Choisir le type de stationnement</string>
<string name="osmand_parking_lim_text">Temps limité</string> <string name="osmand_parking_lim_text">Temps limité</string>
<string name="osmand_parking_no_lim_text">Temps illimité</string> <string name="osmand_parking_no_lim_text">Temps illimité</string>
<string name="osmand_parking_add_event">Ajouter une notification dans l\'Agenda</string> <string name="osmand_parking_add_event">Ajouter une notification dans l\'agenda</string>
<string name="osmand_parking_time_limit">Stationnement avec limite de temps</string> <string name="osmand_parking_time_limit">Stationnement avec limite de temps</string>
<string name="osmand_parking_time_no_limit">Stationnement sans limite de temps</string> <string name="osmand_parking_time_no_limit">Stationnement sans limite de temps</string>
<string name="osmand_parking_position_description">La position de votre véhicule. %1$s</string> <string name="osmand_parking_position_description">La position de votre véhicule. %1$s</string>
@ -1093,7 +1093,7 @@
<string name="no_buildings_found">Aucun numéro de bâtiment trouvé</string> <string name="no_buildings_found">Aucun numéro de bâtiment trouvé</string>
<string name="search_villages_and_postcodes">Rechercher les villages et les codes postaux</string> <string name="search_villages_and_postcodes">Rechercher les villages et les codes postaux</string>
<string name="route_descr_lat_lon">Lat %1$.3f lon %2$.3f</string> <string name="route_descr_lat_lon">Lat %1$.3f lon %2$.3f</string>
<string name="route_descr_current_location">la position actuelle</string> <string name="route_descr_current_location">La position actuelle</string>
<string name="map_widget_max_speed">Limite de vitesse</string> <string name="map_widget_max_speed">Limite de vitesse</string>
@ -1281,7 +1281,7 @@
<string name="clear_destination">Effacer la destination</string> <string name="clear_destination">Effacer la destination</string>
<string name="other_location">Autre</string> <string name="other_location">Autre</string>
<string name="files_limit">Il reste %1$d fichiers</string> <string name="files_limit">Il reste %1$d fichiers</string>
<string name="available_downloads_left">Reste %1$d fichiers à télécharger</string> <string name="available_downloads_left">Vous pouvez encore télécharger %1$d fichier(s).</string>
<string name="install_paid">Version complète</string> <string name="install_paid">Version complète</string>
<string name="use_magnetic_sensor_descr">Utiliser le magnétomètre pour déterminer l\'orientation de la boussole au lieu du capteur d\'orientation</string> <string name="use_magnetic_sensor_descr">Utiliser le magnétomètre pour déterminer l\'orientation de la boussole au lieu du capteur d\'orientation</string>
<string name="use_magnetic_sensor">Utiliser le magnétomètre (boussole)</string> <string name="use_magnetic_sensor">Utiliser le magnétomètre (boussole)</string>
@ -1472,10 +1472,10 @@
<string name="routing_attr_avoid_motorway_description">Éviter les autoroutes</string> <string name="routing_attr_avoid_motorway_description">Éviter les autoroutes</string>
<string name="routing_attr_weight_name">Poids</string> <string name="routing_attr_weight_name">Poids</string>
<string name="routing_attr_weight_description">Spécifier la limite de poids</string> <string name="routing_attr_weight_description">Spécifier la limite de poids</string>
<string name="select_gpx">Sélectionner GPX </string> <string name="select_gpx">Sélectionner GPX…</string>
<string name="route_descr_select_destination">Définir la destination</string> <string name="route_descr_select_destination">Définir la destination</string>
<string name="route_descr_select_on_map">Définir sur la carte </string> <string name="route_descr_select_on_map">Définir sur la carte…</string>
<string name="route_descr_favorite">Favori </string> <string name="route_descr_favorite">Favori…</string>
<string name="route_preferences">Préférences d\'itinéraire</string> <string name="route_preferences">Préférences d\'itinéraire</string>
<string name="route_info">Informations sur l\'itinéraire</string> <string name="route_info">Informations sur l\'itinéraire</string>
<string name="keep_and_add_destination_point">Ajouter comme destination</string> <string name="keep_and_add_destination_point">Ajouter comme destination</string>
@ -1551,18 +1551,22 @@
<string name="interrupt_music_descr">Interrompre la musique lors des annonces</string> <string name="interrupt_music_descr">Interrompre la musique lors des annonces</string>
<string name="interrupt_music">Interrompre la musique</string> <string name="interrupt_music">Interrompre la musique</string>
<string name="share_route_as_gpx">Partager l\'itinéraire au format GPX</string> <string name="share_route_as_gpx">Partager l\'itinéraire au format GPX</string>
<string name="share_route_subject">Itinéraire partagé via OsmAnd</string> <string name="share_route_subject">Itinéraire partagé via OsmAnd</string>
<string name="osmo_settings_uuid">Identifiant unique de l\'appareil</string> <string name="osmo_settings_uuid">Identifiant unique de l\'appareil</string>
<string name="osmo_settings_descr">Voir la clé unique d\'enregistrement de l\'appareil et les autres paramètres spécifiques de suivi</string> <string name="osmo_settings_descr">Voir la clé unique d\'enregistrement de l\'appareil et les autres paramètres spécifiques de suivi</string>
<string name="osmo_plugin_description">OpenStreetMap-Monitoring - Suivi en temps réel avec de nombreuses fonctionnalités de contrôle à distance http://osmo.mobi</string> <string name="osmo_plugin_description">OpenStreetMap-Monitoring - Suivi en temps réel avec de nombreuses fonctionnalités de contrôle à distance http://osmo.mobi</string>
<string name="osmo_plugin_name">OSMo (suivi en temps réel)</string> <string name="osmo_plugin_name">OSMo (suivi en temps réel)</string>
<string name="osmo_settings">OSMo</string> <string name="osmo_settings">OSMo</string>
<string name="keep_informing_never">Jamais</string> <string name="osmo_register_device">Enregistrement de l\'appareil…</string>
<string name="keep_informing_descr">Annoncer les instructions de navigation à intervalles réguliers</string> <string name="osmo_io_error">Problème de connection OSMo : </string>
<string name="keep_informing">Répéter les instructions de navigation</string> <string name="osmo_mode_on">Arrêter\nOSMo</string>
<string name="navigation_intent_invalid">Format invalide : %s</string> <string name="osmo_mode_off">Démarrer\nOSMo</string>
<string name="keep_informing_never">Jamais</string>
<string name="keep_informing_descr">Annoncer les instructions de navigation à intervalles réguliers</string>
<string name="keep_informing">Répéter les instructions de navigation</string>
<string name="navigation_intent_invalid">Format invalide : %s</string>
<string name="arrival_distance">Annonce de l\'arrivée</string> <string name="arrival_distance">Annonce de l\'arrivée</string>
<string name="arrival_distance_descr">Choisir à quel moment est annoncée l\'arrivée à destination</string> <string name="arrival_distance_descr">Choisir à quel moment est annoncée l\'arrivée à destination</string>
<string-array name="arrival_distance_factors"> <string-array name="arrival_distance_factors">
<item>Précoce</item> <item>Précoce</item>
<item>Normale</item> <item>Normale</item>

View file

@ -9,15 +9,31 @@
3. All your modified/created strings are in the top of the file (to make easier find what\'s translated). 3. All your modified/created strings are in the top of the file (to make easier find what\'s translated).
PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy
--> -->
<string name="osmo_io_error">OSMo connection problem : </string> <string name="osmo_auto_send_locations_descr">Automatically start tracker session and send locations after application startup</string>
<string name="osmo_mode_on">Stop OSMo</string> <string name="osmo_auto_send_locations">Automatically start tracker session</string>
<string name="osmo_mode_off">Start OSMo</string> <string name="osmo_tracker_id">Personal tracker id</string>
<string name="osmo_tracker_id_descr">Click to view or share tracker id.
Using tracker id connected devices will be able to monitor all movements of this device! To disconnect select Regenerate option.</string>
<string name="osmo_session_token">Session token : %1$s</string>
<string name="osmo_auth_pending">Waiting for authorization...</string>
<string name="osmo_locations_sent">Locations sent %1$d (in buffer %2$d) </string>
<string name="osmo_conn_successfull">Connection established : %1$s </string>
<string name="osmo_io_error">OsMo connection problem : </string>
<string name="osmo_settings_uuid">Unique device id</string> <string name="osmo_settings_uuid">Unique device id</string>
<string name="osmo_settings_descr">View unique device registration key and other monitoring specific settings </string> <string name="tip_recent_changes_1_8_alpha">Changes in 1.8:
<string name="osmo_settings">OSMo (OpenStreetMap-Monitoring)</string> * Calculate route between route points of GPX track
* Changed layout of countries for downloads (support local names search)
</string>
<string name="use_points_as_intermediates">Calculate route between points</string>
<string name="osmo_mode_restart">Restart OsMo session</string>
<string name="osmo_mode_on">Stop OsMo session</string>
<string name="osmo_mode_off">Start OsMo session</string>
<string name="osmo_settings_debug">Debug information</string>
<string name="osmo_settings_descr">Configure monitoring settings and setup personal monitoring channel</string>
<string name="osmo_settings">OsMo (OpenStreetMap-Monitoring)</string>
<string name="osmo_plugin_description">OpenStreetMap-Monitoring - Advanced Live Monitoring with lots of features for remote control http://osmo.mobi</string> <string name="osmo_plugin_description">OpenStreetMap-Monitoring - Advanced Live Monitoring with lots of features for remote control http://osmo.mobi</string>
<string name="osmo_plugin_name">OSMo (Advanced Live Monitoring)</string> <string name="osmo_plugin_name">OsMo (Advanced Live Monitoring)</string>
<string name="osmo_settings">OSMo</string> <string name="osmo_settings">OsMo</string>
<string name="always_center_position_on_map">Display position always in center</string> <string name="always_center_position_on_map">Display position always in center</string>
<string name="voice_pref_title">Voice</string> <string name="voice_pref_title">Voice</string>
<string name="misc_pref_title">Miscallenious</string> <string name="misc_pref_title">Miscallenious</string>
@ -1441,6 +1457,8 @@ Afghanistan, Albania, Algeria, Andorra, Angola, Anguilla, Antigua and Barbuda, A
<string name="no_fav_to_save">No favorite points to save</string> <string name="no_fav_to_save">No favorite points to save</string>
<string name="import_fav">Import</string> <string name="import_fav">Import</string>
<string name="export_fav">Export</string> <string name="export_fav">Export</string>
<string name="share_fav">Share</string>
<string name="share_fav_subject">Favourites shared via OsmAnd</string>
<string name="error_occurred_loading_gpx">Error occurred while loading GPX</string> <string name="error_occurred_loading_gpx">Error occurred while loading GPX</string>
<string name="send_report">Send report</string> <string name="send_report">Send report</string>
<string name="none_region_found">No offline data for regions found on SD card. Download regions from the Internet.</string> <string name="none_region_found">No offline data for regions found on SD card. Download regions from the Internet.</string>

View file

@ -8,9 +8,9 @@
<CheckBoxPreference android:summary="@string/use_english_names_descr" android:title="@string/use_english_names" <CheckBoxPreference android:summary="@string/use_english_names_descr" android:title="@string/use_english_names"
android:key="use_english_names"></CheckBoxPreference> android:key="use_english_names"></CheckBoxPreference>
<ListPreference android:key="default_driving_region" android:title="@string/driving_region" android:summary="@string/driving_region_descr"></ListPreference> <ListPreference android:key="default_driving_region" android:title="@string/driving_region" android:summary="@string/driving_region_descr"></ListPreference>
<!--
<ListPreference android:key="default_metric_system" android:title="@string/unit_of_length" android:summary="@string/unit_of_length_descr"></ListPreference> <ListPreference android:key="default_metric_system" android:title="@string/unit_of_length" android:summary="@string/unit_of_length_descr"></ListPreference>
-->
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/voice_pref_title" android:key="voice"> <PreferenceCategory android:title="@string/voice_pref_title" android:key="voice">
<ListPreference android:title="@string/voice_provider" android:key="voice_provider" android:summary="@string/voice_provider_descr"></ListPreference> <ListPreference android:title="@string/voice_provider" android:key="voice_provider" android:summary="@string/voice_provider_descr"></ListPreference>

View file

@ -89,6 +89,11 @@ public class FavouritesDbHelper {
public String exportFavorites(String fileName) { public String exportFavorites(String fileName) {
File f = new File(context.getAppPath(null), fileName); File f = new File(context.getAppPath(null), fileName);
GPXFile gpx = asGpxFile();
return GPXUtilities.writeGpxFile(f, gpx, context);
}
public GPXFile asGpxFile() {
GPXFile gpx = new GPXFile(); GPXFile gpx = new GPXFile();
for (FavouritePoint p : getFavouritePoints()) { for (FavouritePoint p : getFavouritePoints()) {
if (p.isStored()) { if (p.isStored()) {
@ -101,7 +106,7 @@ public class FavouritesDbHelper {
gpx.points.add(pt); gpx.points.add(pt);
} }
} }
return GPXUtilities.writeGpxFile(f, gpx, context); return gpx;
} }
private void createCategories(SQLiteConnection db){ private void createCategories(SQLiteConnection db){

View file

@ -124,6 +124,26 @@ public class GPXUtilities {
return "cloudmade".equalsIgnoreCase(author); return "cloudmade".equalsIgnoreCase(author);
} }
public boolean hasRtePt() {
for(Route r : routes) {
if(r.points.size() > 0) {
return true;
}
}
return false;
}
public boolean hasTrkpt() {
for(Track t : tracks) {
for (TrkSegment ts : t.segments) {
if (ts.points.size() > 0) {
return true;
}
}
}
return false;
}
public void proccessPoints() { public void proccessPoints() {
List<List<WptPt>> tpoints = new ArrayList<List<WptPt>>(); List<List<WptPt>> tpoints = new ArrayList<List<WptPt>>();
boolean created = false; boolean created = false;

View file

@ -632,7 +632,8 @@ public class OsmandSettings {
public final OsmandPreference<DrivingRegion> DRIVING_REGION = new EnumIntPreference<DrivingRegion>( public final OsmandPreference<DrivingRegion> DRIVING_REGION = new EnumIntPreference<DrivingRegion>(
"default_driving_region", DrivingRegion.EUROPE_ASIA, DrivingRegion.values()) { "default_driving_region", DrivingRegion.EUROPE_ASIA, DrivingRegion.values()) {
protected boolean setValue(Object prefs, DrivingRegion val) { protected boolean setValue(Object prefs, DrivingRegion val) {
((CommonPreference<MetricsConstants>)METRIC_SYSTEM).cachedValue = null; //((CommonPreference<MetricsConstants>)METRIC_SYSTEM).cachedValue = null;
((CommonPreference<MetricsConstants>)METRIC_SYSTEM).set(DRIVING_REGION.get().defMetrics);
return super.setValue(prefs, val); return super.setValue(prefs, val);
}; };
}.makeGlobal().cache(); }.makeGlobal().cache();
@ -640,7 +641,7 @@ public class OsmandSettings {
// this value string is synchronized with settings_pref.xml preference name // this value string is synchronized with settings_pref.xml preference name
// cache of metrics constants as they are used very often // cache of metrics constants as they are used very often
public final OsmandPreference<MetricsConstants> METRIC_SYSTEM = new EnumIntPreference<MetricsConstants>( public final OsmandPreference<MetricsConstants> METRIC_SYSTEM = new EnumIntPreference<MetricsConstants>(
"default_metric_system_2", MetricsConstants.KILOMETERS_AND_METERS, MetricsConstants.values()){ "default_metric_system", MetricsConstants.KILOMETERS_AND_METERS, MetricsConstants.values()){
protected MetricsConstants getDefaultValue() { protected MetricsConstants getDefaultValue() {
return DRIVING_REGION.get().defMetrics; return DRIVING_REGION.get().defMetrics;
}; };
@ -786,9 +787,10 @@ public class OsmandSettings {
public final OsmandPreference<Boolean> SPEAK_SPEED_CAMERA = new BooleanPreference("speak_cameras", true).makeProfile().cache(); public final OsmandPreference<Boolean> SPEAK_SPEED_CAMERA = new BooleanPreference("speak_cameras", true).makeProfile().cache();
public final OsmandPreference<Boolean> SPEAK_SPEED_LIMIT = new BooleanPreference("speak_speed_limit", true).makeProfile().cache(); public final OsmandPreference<Boolean> SPEAK_SPEED_LIMIT = new BooleanPreference("speak_speed_limit", true).makeProfile().cache();
public final OsmandPreference<Boolean> ROUTE_CALC_OSMAND_PARTS = new BooleanPreference("gpx_routing_calculate_osmand_route", true).makeGlobal().cache(); public final OsmandPreference<Boolean> GPX_ROUTE_CALC_OSMAND_PARTS = new BooleanPreference("gpx_routing_calculate_osmand_route", true).makeGlobal().cache();
public final OsmandPreference<Boolean> SPEAK_GPX_WPT = new BooleanPreference("speak_gpx_wpt", true).makeGlobal().cache(); public final OsmandPreference<Boolean> GPX_CALCULATE_RTEPT = new BooleanPreference("gpx_routing_calculate_rtept", true).makeGlobal().cache();
public final OsmandPreference<Boolean> CALC_GPX_ROUTE = new BooleanPreference("calc_gpx_route", false).makeGlobal().cache(); public final OsmandPreference<Boolean> GPX_SPEAK_WPT = new BooleanPreference("speak_gpx_wpt", true).makeGlobal().cache();
public final OsmandPreference<Boolean> GPX_ROUTE_CALC = new BooleanPreference("calc_gpx_route", false).makeGlobal().cache();
@ -824,6 +826,12 @@ public class OsmandSettings {
public final OsmandPreference<String> MAP_INFO_CONTROLS = new StringPreference("map_info_controls", "").makeProfile(); public final OsmandPreference<String> MAP_INFO_CONTROLS = new StringPreference("map_info_controls", "").makeProfile();
public final OsmandPreference<String> OSMO_DEVICE_KEY = new StringPreference("osmo_device_token", "").makeGlobal();
public final OsmandPreference<Boolean> OSMO_AUTO_SEND_LOCATIONS = new BooleanPreference("osmo_automatically_send_locations", false).makeGlobal();
public final OsmandPreference<String> OSMO_GROUPS = new StringPreference("osmo_groups", "{}").makeGlobal();
// this value string is synchronized with settings_pref.xml preference name // this value string is synchronized with settings_pref.xml preference name
public final OsmandPreference<Boolean> DEBUG_RENDERING_INFO = new BooleanPreference("debug_rendering", false).makeGlobal(); public final OsmandPreference<Boolean> DEBUG_RENDERING_INFO = new BooleanPreference("debug_rendering", false).makeGlobal();
@ -1659,6 +1667,10 @@ public class OsmandSettings {
public static final int OSMAND_DARK_THEME = 0; public static final int OSMAND_DARK_THEME = 0;
public static final int OSMAND_LIGHT_THEME = 1; public static final int OSMAND_LIGHT_THEME = 1;
public static final int OSMAND_LIGHT_DARK_ACTIONBAR_THEME = 2; public static final int OSMAND_LIGHT_DARK_ACTIONBAR_THEME = 2;
public final CommonPreference<Integer> SEARCH_TAB =
new IntPreference("SEARCH_TAB", 0).makeGlobal().cache();
public final CommonPreference<Integer> OSMAND_THEME = public final CommonPreference<Integer> OSMAND_THEME =
new IntPreference("osmand_theme", OSMAND_DARK_THEME).makeGlobal().cache(); new IntPreference("osmand_theme", OSMAND_DARK_THEME).makeGlobal().cache();

View file

@ -15,6 +15,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import android.content.Intent;
import net.londatiga.android.ActionItem; import net.londatiga.android.ActionItem;
import net.londatiga.android.QuickAction; import net.londatiga.android.QuickAction;
import net.osmand.access.AccessibleToast; import net.osmand.access.AccessibleToast;
@ -61,15 +62,11 @@ import com.actionbarsherlock.view.Window;
*/ */
public class FavouritesActivity extends OsmandExpandableListActivity { public class FavouritesActivity extends OsmandExpandableListActivity {
public static final int SHOW_ON_MAP = 0;
public static final int NAVIGATE_TO = 1;
public static final int DELETE_ITEM = 2;
public static final int EDIT_ITEM = 3;
public static final int EXPORT_ID = 0; public static final int EXPORT_ID = 0;
public static final int IMPORT_ID = 1; public static final int IMPORT_ID = 1;
public static final int DELETE_ID = 2; public static final int DELETE_ID = 2;
public static final int DELETE_ACTION_ID = 3; public static final int DELETE_ACTION_ID = 3;
public static final int SHARE_ID = 4;
private FavouritesAdapter favouritesAdapter; private FavouritesAdapter favouritesAdapter;
@ -126,7 +123,7 @@ public class FavouritesActivity extends OsmandExpandableListActivity {
hideProgressBar(); hideProgressBar();
favouritesAdapter.synchronizeGroups(); favouritesAdapter.synchronizeGroups();
favouritesAdapter.sort(favoritesComparator); favouritesAdapter.sort(favoritesComparator);
}; }
@Override @Override
protected void onProgressUpdate(Object... values) { protected void onProgressUpdate(Object... values) {
@ -137,7 +134,7 @@ public class FavouritesActivity extends OsmandExpandableListActivity {
favouritesAdapter.deleteCategory((String) o); favouritesAdapter.deleteCategory((String) o);
} }
} }
}; }
@Override @Override
protected String doInBackground(Void... params) { protected String doInBackground(Void... params) {
@ -285,6 +282,9 @@ public class FavouritesActivity extends OsmandExpandableListActivity {
} else if (item.getItemId() == IMPORT_ID) { } else if (item.getItemId() == IMPORT_ID) {
importFile(); importFile();
return true; return true;
} else if (item.getItemId() == SHARE_ID) {
shareFavourites();
return true;
} else if (item.getItemId() == DELETE_ID) { } else if (item.getItemId() == DELETE_ID) {
enterDeleteMode(); enterDeleteMode();
return true; return true;
@ -301,6 +301,8 @@ public class FavouritesActivity extends OsmandExpandableListActivity {
public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) { public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) {
createMenuItem(menu, EXPORT_ID, R.string.export_fav, R.drawable.ic_action_gsave_light, R.drawable.ic_action_gsave_dark, createMenuItem(menu, EXPORT_ID, R.string.export_fav, R.drawable.ic_action_gsave_light, R.drawable.ic_action_gsave_dark,
MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
createMenuItem(menu, SHARE_ID, R.string.share_fav, R.drawable.ic_action_gshare_light, R.drawable.ic_action_gshare_dark,
MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
createMenuItem(menu, IMPORT_ID, R.string.import_fav, R.drawable.ic_action_grefresh_light, R.drawable.ic_action_grefresh_dark, createMenuItem(menu, IMPORT_ID, R.string.import_fav, R.drawable.ic_action_grefresh_light, R.drawable.ic_action_grefresh_dark,
MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
createMenuItem(menu, DELETE_ID, R.string.default_buttons_delete, R.drawable.ic_action_delete_light, R.drawable.ic_action_delete_dark, createMenuItem(menu, DELETE_ID, R.string.default_buttons_delete, R.drawable.ic_action_delete_light, R.drawable.ic_action_delete_dark,
@ -444,6 +446,37 @@ public class FavouritesActivity extends OsmandExpandableListActivity {
} }
} }
private void shareFavourites() {
if (favouritesAdapter.isEmpty()) {
AccessibleToast.makeText(this, R.string.no_fav_to_save, Toast.LENGTH_LONG).show();
} else {
final AsyncTask<Void, Void, GPXFile> exportTask = new AsyncTask<Void, Void, GPXFile>() {
@Override
protected GPXFile doInBackground(Void... params) {
return helper.asGpxFile();
}
@Override
protected void onPreExecute() {
showProgressBar();
}
@Override
protected void onPostExecute(GPXFile gpxFile) {
hideProgressBar();
final Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, GPXUtilities.asString(gpxFile, getMyApplication()));
sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_fav_subject));
sendIntent.setType("application/gpx+xml");
startActivity(sendIntent);
}
};
exportTask.execute();
}
}
private void export() { private void export() {
final File tosave = getMyApplication().getAppPath(FavouritesDbHelper.FILE_TO_SAVE); final File tosave = getMyApplication().getAppPath(FavouritesDbHelper.FILE_TO_SAVE);
if (favouritesAdapter.isEmpty()) { if (favouritesAdapter.isEmpty()) {

View file

@ -473,9 +473,15 @@ public class MapActivityActions implements DialogProvider {
} else { } else {
GPXRouteParamsBuilder params = new GPXRouteParamsBuilder(result, mapActivity.getMyApplication() GPXRouteParamsBuilder params = new GPXRouteParamsBuilder(result, mapActivity.getMyApplication()
.getSettings()); .getSettings());
params.setCalculateOsmAndRouteParts(settings.ROUTE_CALC_OSMAND_PARTS.get()); if (result.hasRtePt() && !result.hasTrkpt()) {
params.setAnnounceWaypoints(settings.SPEAK_GPX_WPT.get()); settings.GPX_CALCULATE_RTEPT.set(true);
params.setCalculateOsmAndRoute(settings.CALC_GPX_ROUTE.get()); } else {
settings.GPX_CALCULATE_RTEPT.set(false);
}
params.setCalculateOsmAndRouteParts(settings.GPX_ROUTE_CALC_OSMAND_PARTS.get());
params.setAnnounceWaypoints(settings.GPX_SPEAK_WPT.get());
params.setUseIntermediatePointsRTE(settings.GPX_CALCULATE_RTEPT.get());
params.setCalculateOsmAndRoute(settings.GPX_ROUTE_CALC.get());
List<Location> ps = params.getPoints(); List<Location> ps = params.getPoints();
mapActivity.getRoutingHelper().setGpxParams(params); mapActivity.getRoutingHelper().setGpxParams(params);
settings.FOLLOW_THE_GPX_ROUTE.set(result.path); settings.FOLLOW_THE_GPX_ROUTE.set(result.path);

View file

@ -17,6 +17,7 @@ import net.osmand.plus.ApplicationMode;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings; import net.osmand.plus.OsmandSettings;
import net.osmand.plus.OsmandSettings.DrivingRegion; import net.osmand.plus.OsmandSettings.DrivingRegion;
import net.osmand.plus.OsmandSettings.MetricsConstants;
import net.osmand.plus.ProgressDialogImplementation; import net.osmand.plus.ProgressDialogImplementation;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.Version; import net.osmand.plus.Version;
@ -138,16 +139,16 @@ public class SettingsGeneralActivity extends SettingsBaseActivity {
DrivingRegion[] drs = DrivingRegion.values(); DrivingRegion[] drs = DrivingRegion.values();
entries = new String[drs.length]; entries = new String[drs.length];
for (int i = 0; i < entries.length; i++) { for (int i = 0; i < entries.length; i++) {
entries[i] = getString(drs[i].name) + " (" + drs[i].defMetrics.toHumanString(this) +")" ; entries[i] = getString(drs[i].name); // + " (" + drs[i].defMetrics.toHumanString(this) +")" ;
} }
registerListPreference(settings.DRIVING_REGION, screen, entries, drs); registerListPreference(settings.DRIVING_REGION, screen, entries, drs);
// MetricsConstants[] mvls = MetricsConstants.values(); MetricsConstants[] mvls = MetricsConstants.values();
// entries = new String[mvls.length]; entries = new String[mvls.length];
// for(int i=0; i<entries.length; i++){ for(int i=0; i<entries.length; i++){
// entries[i] = mvls[i].toHumanString(getMyApplication()); entries[i] = mvls[i].toHumanString(getMyApplication());
// } }
// registerListPreference(settings.METRIC_SYSTEM, screen, entries, mvls); registerListPreference(settings.METRIC_SYSTEM, screen, entries, mvls);
String incompleteSuffix = " (" + getString(R.string.incomplete_locale) + ")"; String incompleteSuffix = " (" + getString(R.string.incomplete_locale) + ")";
//getResources().getAssets().getLocales(); //getResources().getAssets().getLocales();

View file

@ -20,6 +20,7 @@ import net.osmand.plus.routing.RouteDirectionInfo;
import net.osmand.plus.routing.RoutingHelper; import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.views.TurnPathHelper; import net.osmand.plus.views.TurnPathHelper;
import net.osmand.plus.views.controls.MapRouteInfoControl; import net.osmand.plus.views.controls.MapRouteInfoControl;
import net.osmand.util.Algorithms;
import android.os.Bundle; import android.os.Bundle;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -156,16 +157,8 @@ public class ShowRouteInfoActivity extends OsmandListActivity {
} }
private String getTimeDescription(RouteDirectionInfo model) { private String getTimeDescription(RouteDirectionInfo model) {
int seconds = model.getExpectedTime() % 60; final int timeInSeconds = model.getExpectedTime();
int min = (model.getExpectedTime() / 60) % 60; return Algorithms.formatDuration(timeInSeconds);
int hours = (model.getExpectedTime() / 3600);
String timeText;
if (hours == 0) {
timeText = String.format("%02d:%02d", min, seconds); //$NON-NLS-1$
} else {
timeText = String.format("%d:%02d:%02d", hours, min, seconds); //$NON-NLS-1$
}
return timeText;
} }
} }

View file

@ -56,8 +56,6 @@ public class SearchActivity extends SherlockFragmentActivity implements OsmAndLo
public static final int HISTORY_TAB_INDEX = 3; public static final int HISTORY_TAB_INDEX = 3;
public static final int TRANSPORT_TAB_INDEX = 4; public static final int TRANSPORT_TAB_INDEX = 4;
public static final String TAB_INDEX_EXTRA = "TAB_INDEX_EXTRA";
protected static final int POSITION_CURRENT_LOCATION = 1; protected static final int POSITION_CURRENT_LOCATION = 1;
protected static final int POSITION_LAST_MAP_VIEW = 2; protected static final int POSITION_LAST_MAP_VIEW = 2;
protected static final int POSITION_FAVORITES = 3; protected static final int POSITION_FAVORITES = 3;
@ -106,6 +104,7 @@ public class SearchActivity extends SherlockFragmentActivity implements OsmAndLo
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
setContentView(R.layout.search_main); setContentView(R.layout.search_main);
settings = ((OsmandApplication) getApplication()).getSettings(); settings = ((OsmandApplication) getApplication()).getSettings();
Integer tab = settings.SEARCH_TAB.get();
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(""); getSupportActionBar().setTitle("");
// getSupportActionBar().setTitle(R.string.select_search_position); // getSupportActionBar().setTitle(R.string.select_search_position);
@ -119,7 +118,7 @@ public class SearchActivity extends SherlockFragmentActivity implements OsmAndLo
tabHost.setup(); tabHost.setup();
ViewPager mViewPager = (ViewPager)findViewById(R.id.pager); ViewPager mViewPager = (ViewPager)findViewById(R.id.pager);
mTabsAdapter = new TabsAdapter(this, tabHost, tabinfo, mViewPager); mTabsAdapter = new TabsAdapter(this, tabHost, tabinfo, mViewPager, settings);
TabSpec poiTab = tabHost.newTabSpec(SEARCH_POI).setIndicator(getTabIndicator(tabHost, R.drawable.tab_search_poi_icon, R.string.poi)); TabSpec poiTab = tabHost.newTabSpec(SEARCH_POI).setIndicator(getTabIndicator(tabHost, R.drawable.tab_search_poi_icon, R.string.poi));
mTabsAdapter.addTab(poiTab, SearchPoiFilterActivity.class, null); mTabsAdapter.addTab(poiTab, SearchPoiFilterActivity.class, null);
@ -135,22 +134,15 @@ public class SearchActivity extends SherlockFragmentActivity implements OsmAndLo
mTabsAdapter.addTab(historyTab, SearchHistoryFragment.class, null); mTabsAdapter.addTab(historyTab, SearchHistoryFragment.class, null);
TabSpec transportTab = tabHost.newTabSpec(SEARCH_TRANSPORT).setIndicator(getTabIndicator(tabHost, R.drawable.tab_search_transport_icon, R.string.transport)); TabSpec transportTab = tabHost.newTabSpec(SEARCH_TRANSPORT).setIndicator(getTabIndicator(tabHost, R.drawable.tab_search_transport_icon, R.string.transport));
mTabsAdapter.addTab(transportTab, SearchTransportFragment.class, null); mTabsAdapter.addTab(transportTab, SearchTransportFragment.class, null);
tabHost.setCurrentTab(POI_TAB_INDEX); tabHost.setCurrentTab(tab);
if (savedInstanceState != null) {
tabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
}
setTopSpinner(); setTopSpinner();
Log.i("net.osmand", "Start on create " + (System.currentTimeMillis() - t )); Log.i("net.osmand", "Start on create " + (System.currentTimeMillis() - t ));
Intent intent = getIntent(); Intent intent = getIntent();
int tabIndex = 0; OsmandSettings settings = ((OsmandApplication) getApplication()).getSettings();
if (intent != null) { if (intent != null) {
if(intent.hasExtra(TAB_INDEX_EXTRA)){
tabIndex = intent.getIntExtra(TAB_INDEX_EXTRA, POI_TAB_INDEX);
mTabsAdapter.mTabHost.setCurrentTab(tabIndex);
}
double lat = intent.getDoubleExtra(SEARCH_LAT, 0); double lat = intent.getDoubleExtra(SEARCH_LAT, 0);
double lon = intent.getDoubleExtra(SEARCH_LON, 0); double lon = intent.getDoubleExtra(SEARCH_LON, 0);
if (lat != 0 || lon != 0) { if (lat != 0 || lon != 0) {
@ -234,7 +226,6 @@ public class SearchActivity extends SherlockFragmentActivity implements OsmAndLo
@Override @Override
protected void onSaveInstanceState(Bundle outState) { protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
outState.putString("tab", mTabsAdapter.mTabHost.getCurrentTabTag());
} }
@ -358,7 +349,6 @@ public class SearchActivity extends SherlockFragmentActivity implements OsmAndLo
// mTabsAdapter.notifyDataSetChanged(); // mTabsAdapter.notifyDataSetChanged();
// mTabsAdapter.mViewPager.invalidate(); // mTabsAdapter.mViewPager.invalidate();
Intent intent = getIntent(); Intent intent = getIntent();
intent.putExtra(TAB_INDEX_EXTRA, ADDRESS_TAB_INDEX);
finish(); finish();
startActivity(intent); startActivity(intent);
} }
@ -382,6 +372,7 @@ public class SearchActivity extends SherlockFragmentActivity implements OsmAndLo
private final ViewPager mViewPager; private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
private TextView tabInfo; private TextView tabInfo;
private OsmandSettings osmSettings;
static final class TabInfo { static final class TabInfo {
private final String tag; private final String tag;
@ -411,12 +402,13 @@ public class SearchActivity extends SherlockFragmentActivity implements OsmAndLo
} }
} }
public TabsAdapter(FragmentActivity activity, TabHost tabHost, TextView tabinfo, ViewPager pager) { public TabsAdapter(FragmentActivity activity, TabHost tabHost, TextView tabinfo, ViewPager pager, OsmandSettings settings) {
super(activity.getSupportFragmentManager()); super(activity.getSupportFragmentManager());
mContext = activity; mContext = activity;
mTabHost = tabHost; mTabHost = tabHost;
tabInfo = tabinfo; tabInfo = tabinfo;
mViewPager = pager; mViewPager = pager;
osmSettings = settings;
mTabHost.setOnTabChangedListener(this); mTabHost.setOnTabChangedListener(this);
mViewPager.setAdapter(this); mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this); mViewPager.setOnPageChangeListener(this);
@ -447,6 +439,7 @@ public class SearchActivity extends SherlockFragmentActivity implements OsmAndLo
@Override @Override
public void onTabChanged(String tabId) { public void onTabChanged(String tabId) {
int position = mTabHost.getCurrentTab(); int position = mTabHost.getCurrentTab();
osmSettings.SEARCH_TAB.set(position);
mViewPager.setCurrentItem(position); mViewPager.setCurrentItem(position);
if (SEARCH_POI.equals(tabId)) { if (SEARCH_POI.equals(tabId)) {
tabInfo.setText(R.string.poi_search_desc); tabInfo.setText(R.string.poi_search_desc);

View file

@ -128,13 +128,16 @@ public class FailSafeFuntions {
final GPXRouteParamsBuilder gpxRoute; final GPXRouteParamsBuilder gpxRoute;
if (result != null) { if (result != null) {
gpxRoute = new GPXRouteParamsBuilder(result, settings); gpxRoute = new GPXRouteParamsBuilder(result, settings);
if (settings.SPEAK_GPX_WPT.get()) { if (settings.GPX_SPEAK_WPT.get()) {
gpxRoute.setAnnounceWaypoints(true); gpxRoute.setAnnounceWaypoints(true);
} }
if (settings.ROUTE_CALC_OSMAND_PARTS.get()) { if (settings.GPX_ROUTE_CALC_OSMAND_PARTS.get()) {
gpxRoute.setCalculateOsmAndRouteParts(true); gpxRoute.setCalculateOsmAndRouteParts(true);
} }
if(settings.CALC_GPX_ROUTE.get()) { if (settings.GPX_CALCULATE_RTEPT.get()) {
gpxRoute.setUseIntermediatePointsRTE(true);
}
if(settings.GPX_ROUTE_CALC.get()) {
gpxRoute.setCalculateOsmAndRoute(true); gpxRoute.setCalculateOsmAndRoute(true);
} }
} else { } else {

View file

@ -0,0 +1,283 @@
package net.osmand.plus.osmo;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import net.osmand.data.LatLon;
import net.osmand.plus.OsmandSettings;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class OsMoGroups implements OsMoReactor {
private static final String TRACKER_ID = "trackerId";
private static final String GROUP_TRACKERS = "group_trackers";
private static final String GROUP_ID = "group_id";
private static final String NAME = "name";
private static final String USER_NAME = "userName";
private static final String GROUP_NAME = "group_name";
private static final String MY_GROUP_TRACKER_ID = "my_group_tracker_id";
private OsMoTracker tracker;
private ConcurrentHashMap<String, OsMoGroup> groups = new ConcurrentHashMap<String, OsMoGroup>();
private OsMoGroup mainGroup;
private OsmandSettings settings;
private OsMoService service;
public static class OsMoGroup {
public String name;
public String userName;
public String groupId;
public String myGroupTrackerId;
public boolean active;
public Map<String, OsMoUser> users = new ConcurrentHashMap<String, OsMoGroups.OsMoUser>();
public boolean isMainGroup() {
return groupId == null;
}
public String getVisibleName(){
if(userName != null && userName.length() > 0) {
return userName;
}
return name;
}
}
public static class OsMoMessage {
public long timestamp;
public LatLon location;
public String text;
}
public static class OsMoUser {
public String serverName;
public String userName;
public String trackerId;
public List<OsMoMessage> messages = new ArrayList<OsMoMessage>();
public String getVisibleName(){
if(userName != null && userName.length() > 0) {
return userName;
}
return serverName;
}
}
public OsMoGroups(OsMoService service, OsMoTracker tracker, OsmandSettings settings) {
this.service = service;
this.tracker = tracker;
this.settings = settings;
// service.registerSender(this);
service.registerReactor(this);
mainGroup = new OsMoGroup();
groups.put("", mainGroup);
parseGroups();
}
private void parseGroups() {
String grp = settings.OSMO_GROUPS.get();
try {
JSONObject obj = new JSONObject(grp);
parseGroupUsers(mainGroup, obj);
if(!obj.has("groups")) {
return;
}
JSONArray groups = obj.getJSONArray("groups");
for (int i = 0; i < groups.length(); i++) {
JSONObject o = (JSONObject) groups.get(i);
OsMoGroup group = new OsMoGroup();
group.groupId = o.getString(GROUP_ID);
if(o.has(MY_GROUP_TRACKER_ID)) {
group.myGroupTrackerId = o.getString(MY_GROUP_TRACKER_ID);
}
if(o.has(NAME)) {
group.name = o.getString(NAME);
}
if(o.has(USER_NAME)) {
group.userName = o.getString(USER_NAME);
}
parseGroupUsers(group, o);
this.groups.put(group.groupId, group);
}
} catch (JSONException e) {
e.printStackTrace();
service.showErrorMessage(e.getMessage());
}
}
public void saveGroups() {
JSONObject mainObj = new JSONObject();
try {
saveGroupUsers(mainGroup, mainObj);
JSONArray ar = new JSONArray();
for(OsMoGroup gr : groups.values()) {
if(gr.isMainGroup()) {
continue;
}
JSONObject obj = new JSONObject();
if (gr.userName != null) {
obj.put(USER_NAME, gr.userName);
}
if (gr.name != null) {
obj.put(NAME, gr.name);
}
obj.put(GROUP_ID, gr.groupId);
ar.put(obj);
}
} catch (JSONException e) {
e.printStackTrace();
service.showErrorMessage(e.getMessage());
}
settings.OSMO_GROUPS.set(mainObj.toString());
}
private void saveGroupUsers(OsMoGroup gr, JSONObject grObj) throws JSONException {
JSONArray ar = new JSONArray();
for(OsMoUser u : gr.users.values()) {
JSONObject obj = new JSONObject();
if (u.userName != null) {
obj.put(USER_NAME, u.userName);
}
if (u.serverName != null) {
obj.put("serverName", u.serverName);
}
obj.put(TRACKER_ID, u.trackerId);
ar.put(obj);
}
grObj.put("users", ar);
}
private void parseGroupUsers(OsMoGroup gr, JSONObject obj) throws JSONException {
if(!obj.has("users")) {
return;
}
JSONArray users = obj.getJSONArray("users");
for (int i = 0; i < users.length(); i++) {
JSONObject o = (JSONObject) users.get(i);
OsMoUser user = new OsMoUser();
if(o.has("serverName")) {
user.serverName = o.getString("serverName");
}
if(o.has(USER_NAME)) {
user.userName = o.getString(USER_NAME);
}
user.trackerId = o.getString(TRACKER_ID);
}
}
@Override
public boolean acceptCommand(String command, String data, JSONObject obj, OsMoThread thread) {
if(command.startsWith("ON_GROUP_CHANGE:")) {
String gid = command.substring(command.indexOf(':') + 1);
OsMoGroup gr = groups.get(gid);
if(gr != null) {
mergeGroup(gr, obj, false);
}
return true;
} else if(command.startsWith("CREATE_GROUP:")) {
String gid = command.substring(command.indexOf(':') + 1);
OsMoGroup gr = new OsMoGroup();
gr.groupId = gid;
try {
gr.name = obj.getString(GROUP_NAME);
} catch (JSONException e) {
e.printStackTrace();
service.showErrorMessage(e.getMessage());
}
joinGroup(gid);
} else if(command.startsWith("JOIN_GROUP:")) {
String gid = command.substring(command.indexOf(':') + 1);
OsMoGroup gr = groups.get(gid);
if(gr != null) {
mergeGroup(gr, obj, true);
gr.active = true;
for(String key : gr.users.keySet()) {
if (!key.equals(gr.myGroupTrackerId)) {
tracker.startTrackingId(key);
}
}
}
return true;
} else if(command.startsWith("LEAVE_GROUP:")) {
String gid = command.substring(command.indexOf(':') + 1);
OsMoGroup gr = groups.get(gid);
if(gr != null) {
gr.active = false;
for(String key : gr.users.keySet()) {
if (!key.equals(gr.myGroupTrackerId)) {
tracker.stopTrackingId(key);
}
}
}
return true;
}
return false;
}
private void mergeGroup(OsMoGroup gr, JSONObject obj, boolean deleteUsers) {
try {
if(obj.has(GROUP_NAME)) {
gr.name = obj.getString(GROUP_NAME);
}
if(obj.has(MY_GROUP_TRACKER_ID)) {
gr.myGroupTrackerId = obj.getString(MY_GROUP_TRACKER_ID);
}
JSONArray arr = obj.getJSONArray(GROUP_TRACKERS);
Set<String> toDelete = new HashSet<String>(gr.users.keySet());
for (int i = 0; i < arr.length(); i++) {
JSONObject o = (JSONObject) arr.get(i);
String tid = o.getString(TRACKER_ID);
toDelete.remove(tid);
OsMoUser us = gr.users.get(tid);
if (us == null) {
us = new OsMoUser();
us.trackerId = tid;
gr.users.put(tid, us);
if(gr.active) {
if (!tid.equals(gr.myGroupTrackerId)) {
tracker.startTrackingId(tid);
}
}
}
if (o.has(NAME)) {
us.serverName = o.getString(NAME);
}
}
if(deleteUsers) {
for(String s : toDelete) {
gr.users.remove(s);
if(gr.active) {
tracker.stopTrackingId(s);
}
}
}
} catch (JSONException e) {
e.printStackTrace();
service.showErrorMessage(e.getMessage());
}
}
public void joinGroup(String groupId) {
service.pushCommand("JOIN_GROUP|"+groupId);
}
public void createGroup(String groupName) {
service.pushCommand("CREATE_GROUP|{\"group_name\":\"" + groupName + "\"}");
}
public void leaveGroup(OsMoGroup group) {
service.pushCommand("LEAVE_GROUP|"+group.groupId);
}
}

View file

@ -1,7 +1,6 @@
package net.osmand.plus.osmo; package net.osmand.plus.osmo;
import net.osmand.Location; import net.osmand.Location;
import net.osmand.PlatformUtil;
import net.osmand.plus.ContextMenuAdapter; import net.osmand.plus.ContextMenuAdapter;
import net.osmand.plus.ContextMenuAdapter.OnContextMenuClick; import net.osmand.plus.ContextMenuAdapter.OnContextMenuClick;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
@ -12,36 +11,42 @@ import net.osmand.plus.activities.SettingsActivity;
import net.osmand.plus.views.MonitoringInfoControl; import net.osmand.plus.views.MonitoringInfoControl;
import net.osmand.plus.views.MonitoringInfoControl.MonitoringInfoControlServices; import net.osmand.plus.views.MonitoringInfoControl.MonitoringInfoControlServices;
import net.osmand.plus.views.OsmandMapTileView; import net.osmand.plus.views.OsmandMapTileView;
import org.apache.commons.logging.Log;
import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.preference.Preference; import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener; import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
import android.provider.Settings;
public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlServices { public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlServices {
private OsmandApplication app; private OsmandApplication app;
public static final String ID = "osmand.osmo"; public static final String ID = "osmand.osmo";
//private static final Log log = PlatformUtil.getLog(OsMoPlugin.class);
private OsMoService service; private OsMoService service;
private OsMoTracker tracker; private OsMoTracker tracker;
private OsMoGroups groups;
public OsMoPlugin(final OsmandApplication app) { public OsMoPlugin(final OsmandApplication app) {
service = new OsMoService(); service = new OsMoService(app);
tracker = new OsMoTracker(service); tracker = new OsMoTracker(service);
if(app.getSettings().OSMO_AUTO_SEND_LOCATIONS.get()) {
tracker.enableTracker();
}
groups = new OsMoGroups(service, tracker, app.getSettings());
this.app = app; this.app = app;
} }
@Override @Override
public boolean init(final OsmandApplication app) { public boolean init(final OsmandApplication app) {
service.connect(true);
return true; return true;
} }
@Override
public void disable(OsmandApplication app) {
super.disable(app);
service.disconnect();
}
@Override @Override
public void updateLocation(Location location) { public void updateLocation(Location location) {
if (service.isConnected()) { if (service.isConnected()) {
@ -49,10 +54,6 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer
} }
} }
public static String getUUID(Context ctx) {
return Settings.Secure.getString(ctx.getContentResolver(), Settings.Secure.ANDROID_ID);
}
@Override @Override
public String getDescription() { public String getDescription() {
return app.getString(R.string.osmo_plugin_description); return app.getString(R.string.osmo_plugin_description);
@ -73,26 +74,27 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer
} }
} }
@Override @Override
public void addMonitorActions(ContextMenuAdapter qa, MonitoringInfoControl li, final OsmandMapTileView view) { public void addMonitorActions(ContextMenuAdapter qa, MonitoringInfoControl li, final OsmandMapTileView view) {
final boolean off = !service.isConnected(); //final boolean off = !service.isConnected();
qa.item(off ? R.string.osmo_mode_off : R.string.osmo_mode_on) final boolean autosend = app.getSettings().OSMO_AUTO_SEND_LOCATIONS.get();
.icon(off ? R.drawable.monitoring_rec_inactive : R.drawable.monitoring_rec_big) final boolean offTracker = tracker.isEnabledTracker();
qa.item(autosend ? R.string.osmo_mode_restart :
( offTracker ? R.string.osmo_mode_off : R.string.osmo_mode_on))
.icon(offTracker ? R.drawable.monitoring_rec_inactive : R.drawable.monitoring_rec_big)
.listen(new OnContextMenuClick() { .listen(new OnContextMenuClick() {
@Override @Override
public void onContextMenuClick(int itemId, int pos, boolean isChecked, DialogInterface dialog) { public void onContextMenuClick(int itemId, int pos, boolean isChecked, DialogInterface dialog) {
if(off) { if(autosend) {
service.connect(true); tracker.disableTracker();
tracker.enableTracker();
} else if (offTracker) {
tracker.enableTracker();
} else { } else {
service.disconnect(); tracker.disableTracker();
} }
} }
}).reg(); }).reg();
qa.item("Test (send)").icons(R.drawable.ic_action_grefresh_dark, R.drawable.ic_action_grefresh_light) qa.item("Test (send)").icons(R.drawable.ic_action_grefresh_dark, R.drawable.ic_action_grefresh_light)
.listen(new OnContextMenuClick() { .listen(new OnContextMenuClick() {
@ -127,4 +129,16 @@ public class OsMoPlugin extends OsmandPlugin implements MonitoringInfoControlSer
public String getId() { public String getId() {
return ID; return ID;
} }
public OsMoGroups getGroups() {
return groups;
}
public OsMoTracker getTracker() {
return tracker;
}
public OsMoService getService() {
return service;
}
} }

View file

@ -0,0 +1,9 @@
package net.osmand.plus.osmo;
import org.json.JSONObject;
public interface OsMoReactor {
public boolean acceptCommand(String command, String data, JSONObject obj, OsMoThread tread);
}

View file

@ -0,0 +1,6 @@
package net.osmand.plus.osmo;
public interface OsMoSender {
public String nextSendCommand(OsMoThread tracker);
}

View file

@ -1,32 +1,62 @@
package net.osmand.plus.osmo; package net.osmand.plus.osmo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
public class OsMoService { import net.osmand.PlatformUtil;
//public static int NUMBER_OF_TRIES_TO_RECONNECT = 20; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import org.apache.commons.logging.Log;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;
import org.json.JSONObject;
import android.os.Build;
import android.provider.Settings.Secure;
public class OsMoService implements OsMoSender {
private OsMoThread thread; private OsMoThread thread;
private List<OsMoSender> listSenders = new java.util.concurrent.CopyOnWriteArrayList<OsMoSender>(); private List<OsMoSender> listSenders = new java.util.concurrent.CopyOnWriteArrayList<OsMoSender>();
private List<OsMoReactor> listReactors = new java.util.concurrent.CopyOnWriteArrayList<OsMoReactor>(); private List<OsMoReactor> listReactors = new java.util.concurrent.CopyOnWriteArrayList<OsMoReactor>();
private ConcurrentLinkedQueue<String> commands = new ConcurrentLinkedQueue<String>();
private OsmandApplication app;
private static final Log log = PlatformUtil.getLog(OsMoService.class);
private String lastRegistrationError = null;
public interface OsMoSender {
public String nextSendCommand();
}
public interface OsMoReactor { public OsMoService(OsmandApplication app) {
this.app = app;
public boolean acceptCommand(String command); listSenders.add(this);
}
public OsMoService() {
} }
public boolean isConnected() { public boolean isConnected() {
return thread != null && thread.isConnected(); return thread != null && thread.isConnected();
} }
public long getConnectionTime() {
return thread == null || !thread.isConnected() ? System.currentTimeMillis() : thread.getConnectionTime();
}
public String getLastRegistrationError() {
return lastRegistrationError;
}
public boolean connect(boolean forceReconnect) { public boolean connect(boolean forceReconnect) {
if(thread != null) { if(thread != null) {
if(!forceReconnect ) { if(!forceReconnect ) {
@ -34,7 +64,7 @@ public class OsMoService {
} }
thread.stopConnection(); thread.stopConnection();
} }
thread = new OsMoThread(listSenders, listReactors); thread = new OsMoThread(this, listSenders, listReactors);
return true; return true;
} }
@ -65,4 +95,124 @@ public class OsMoService {
} }
public String registerOsmoDeviceKey() throws IOException {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://api.osmo.mobi/auth");
try {
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("android_id", Secure.ANDROID_ID));
nameValuePairs.add(new BasicNameValuePair("android_model", Build.MODEL));
nameValuePairs.add(new BasicNameValuePair("imei", "0"));
nameValuePairs.add(new BasicNameValuePair("android_product", Build.PRODUCT));
nameValuePairs.add(new BasicNameValuePair("osmand", Version.getFullVersion(app)));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
InputStream cm = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(cm));
String r = reader.readLine();
reader.close();
log.info("Authorization key : " + r);
final JSONObject obj = new JSONObject(r);
if(obj.has("error")) {
lastRegistrationError = obj.getString("error");
throw new RuntimeException(obj.getString("error"));
}
app.getSettings().OSMO_DEVICE_KEY.set(obj.getString("key"));
return obj.getString("key");
} catch (JSONException e) {
throw new IOException(e);
}
}
public static class SessionInfo {
public String hostName;
public String port;
public String token;
// after auth
public String protocol = "";
public String groupTrackerId;
public String trackerId;
public String username;
public long serverTimeDelta;
public long motdTimestamp;
}
public SessionInfo getCurrentSessionInfo() {
if(thread == null) {
return null;
}
return thread.getSessionInfo();
}
public SessionInfo prepareSessionToken() throws IOException {
String deviceKey = app.getSettings().OSMO_DEVICE_KEY.get();
if(deviceKey.length() == 0) {
deviceKey = registerOsmoDeviceKey();
}
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://api.osmo.mobi/prepare");
try {
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("key", deviceKey));
nameValuePairs.add(new BasicNameValuePair("protocol", "1"));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
InputStream cm = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(cm));
String r = reader.readLine();
reader.close();
log.info("Authorization key : " + r);
final JSONObject obj = new JSONObject(r);
if(obj.has("error")) {
lastRegistrationError = obj.getString("error");
throw new RuntimeException(obj.getString("error"));
}
if(!obj.has("address")) {
lastRegistrationError = "Host name not specified";
throw new RuntimeException("Host name not specified");
}
if(!obj.has("token")) {
lastRegistrationError = "Token not specified by server";
throw new RuntimeException("Token not specified by server");
}
SessionInfo si = new SessionInfo();
String a = obj.getString("address");
int i = a.indexOf(':');
si.hostName = a.substring(0, i);
si.port = a.substring(i + 1);
si.token = obj.getString("token");
return si;
} catch (ClientProtocolException e) {
throw new IOException(e);
} catch (IOException e) {
throw e;
} catch (JSONException e) {
throw new IOException(e);
}
}
public void showErrorMessage(String string) {
app.showToastMessage(app.getString(R.string.osmo_io_error) + string);
}
public void pushCommand(String cmd) {
commands.add(cmd);
}
@Override
public String nextSendCommand(OsMoThread tracker) {
if(!commands.isEmpty()) {
return commands.poll();
}
return null;
}
} }

View file

@ -10,65 +10,63 @@ import java.nio.channels.SocketChannel;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import net.osmand.PlatformUtil; import net.osmand.PlatformUtil;
import net.osmand.plus.osmo.OsMoService.OsMoReactor; import net.osmand.plus.osmo.OsMoService.SessionInfo;
import net.osmand.plus.osmo.OsMoService.OsMoSender;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.json.JSONException;
import org.json.JSONObject;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.Message; import android.os.Message;
public class OsMoThread { public class OsMoThread {
private static String TRACKER_SERVER = "srv.osmo.mobi"; // private static String TRACKER_SERVER = "srv.osmo.mobi";
private static int TRACKER_PORT = 4242; // private static int TRACKER_PORT = 3245;
protected final static Log log = PlatformUtil.getLog(OsMoThread.class); protected final static Log log = PlatformUtil.getLog(OsMoThread.class);
private static final long HEARTBEAT_DELAY = 100; private static final long HEARTBEAT_DELAY = 100;
private static final long HEARTBEAT_FAILED_DELAY = 10000; private static final long HEARTBEAT_FAILED_DELAY = 10000;
private static final long LIMIT_OF_FAILURES_RECONNECT = 10; private static final long LIMIT_OF_FAILURES_RECONNECT = 10;
private static final long CONNECTION_DELAY = 25000;
private static final long SELECT_TIMEOUT = 500; private static final long SELECT_TIMEOUT = 500;
private static int HEARTBEAT_MSG = 3; private static int HEARTBEAT_MSG = 3;
private Handler serviceThread; private Handler serviceThread;
private int failures = 0; private int failures = 0;
private int activeConnectionId = 0; private int activeConnectionId = 0;
// -1 means connected, 0 needs to reconnect, > 0 when connection initiated
private long connectionStarted = 0;
private boolean stopThread; private boolean stopThread;
private boolean reconnect;
private Selector selector; private Selector selector;
private List<OsMoSender> listSenders; private List<OsMoSender> listSenders;
private List<OsMoReactor> listReactors; private List<OsMoReactor> listReactors;
private int authorized = 0; // 1 - send, 2 - authorized
private OsMoService service;
private SessionInfo sessionInfo = null;
private SocketChannel activeChannel; private SocketChannel activeChannel;
private long connectionTime;
private ByteBuffer pendingSendCommand; private ByteBuffer pendingSendCommand;
private String readCommand = ""; private String readCommand = "";
private ByteBuffer pendingReadCommand = ByteBuffer.allocate(2048); private ByteBuffer pendingReadCommand = ByteBuffer.allocate(2048);
private LinkedList<String> queueOfMessages = new LinkedList<String>(); private LinkedList<String> queueOfMessages = new LinkedList<String>();
public OsMoThread(List<OsMoSender> listSenders, List<OsMoReactor> listReactors) {
public OsMoThread(OsMoService service, List<OsMoSender> listSenders, List<OsMoReactor> listReactors) {
this.service = service;
this.listSenders = listSenders; this.listSenders = listSenders;
this.listReactors = listReactors; this.listReactors = listReactors;
// start thread to receive events from OSMO // start thread to receive events from OSMO
HandlerThread h = new HandlerThread("OSMo Service"); HandlerThread h = new HandlerThread("OSMo Service");
h.start(); h.start();
serviceThread = new Handler(h.getLooper()); serviceThread = new Handler(h.getLooper());
serviceThread.post(new Runnable() {
@Override
public void run() {
try {
initConnection();
} catch (IOException e) {
e.printStackTrace();
}
}
});
scheduleHeartbeat(HEARTBEAT_DELAY); scheduleHeartbeat(HEARTBEAT_DELAY);
} }
@ -77,16 +75,38 @@ public class OsMoThread {
} }
protected void initConnection() throws IOException { protected void initConnection() throws IOException {
try { if (sessionInfo == null) {
sessionInfo = service.prepareSessionToken();
}
authorized = 0;
reconnect = false;
selector = Selector.open(); selector = Selector.open();
connectionStarted = System.currentTimeMillis(); SocketChannel activeChannel = SocketChannel.open();
activeChannel = SocketChannel.open(); activeChannel.configureBlocking(true);
activeChannel.connect(new InetSocketAddress(sessionInfo.hostName, Integer.parseInt(sessionInfo.port)));
activeChannel.configureBlocking(false); activeChannel.configureBlocking(false);
SelectionKey key = activeChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); SelectionKey key = activeChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
connectionTime = System.currentTimeMillis();
if (this.activeChannel != null) {
stopChannel();
}
this.activeChannel = activeChannel;
key.attach(new Integer(++activeConnectionId)); key.attach(new Integer(++activeConnectionId));
activeChannel.connect(new InetSocketAddress(TRACKER_SERVER, TRACKER_PORT));
} catch (IOException e) { }
throw e;
public String format(String cmd, Map<String, Object> params) {
JSONObject json;
try {
json = new JSONObject();
Iterator<Entry<String, Object>> it = params.entrySet().iterator();
while(it.hasNext()) {
Entry<String, Object> e = it.next();
json.put(e.getKey(), e.getValue());
}
return cmd + "|"+json.toString();
} catch (JSONException e) {
throw new RuntimeException(e);
} }
} }
@ -102,26 +122,19 @@ public class OsMoThread {
} }
public boolean isConnected() { public boolean isConnected() {
return connectionStarted == -1; return activeChannel != null;
} }
protected void checkAsyncSocket() { protected void checkAsyncSocket() {
long delay = HEARTBEAT_DELAY; long delay = HEARTBEAT_DELAY;
try { try {
if (selector == null) { // if (selector == null) {
stopThread = true; // stopThread = true;
} else { if(activeChannel == null || reconnect) {
if (activeChannel != null && connectionStarted != -1 && !activeChannel.isConnectionPending()) {
// connection ready
connectionStarted = -1;
}
if ((connectionStarted != -1 && System.currentTimeMillis() - connectionStarted > CONNECTION_DELAY)
|| activeChannel == null) {
initConnection(); initConnection();
} else { } else {
checkSelectedKeys(); checkSelectedKeys();
} }
}
} catch (Exception e) { } catch (Exception e) {
log.info("Exception selecting socket", e); log.info("Exception selecting socket", e);
e.printStackTrace(); e.printStackTrace();
@ -130,7 +143,7 @@ public class OsMoThread {
activeChannel = null; activeChannel = null;
} }
if (failures++ > LIMIT_OF_FAILURES_RECONNECT) { if (failures++ > LIMIT_OF_FAILURES_RECONNECT) {
stopChannel(); reconnect = true;
} }
} }
if (stopThread) { if (stopThread) {
@ -186,12 +199,14 @@ public class OsMoThread {
while (hasSomethingToRead) { while (hasSomethingToRead) {
pendingReadCommand.clear(); pendingReadCommand.clear();
int read = activeChannel.read(pendingReadCommand); int read = activeChannel.read(pendingReadCommand);
if (pendingReadCommand.hasRemaining()) { if (!pendingReadCommand.hasRemaining()) {
hasSomethingToRead = true; hasSomethingToRead = true;
} else { } else {
hasSomethingToRead = false; hasSomethingToRead = false;
} }
if (read > 0) { if(read == -1) {
reconnect = true;
} else if (read > 0) {
byte[] ar = pendingReadCommand.array(); byte[] ar = pendingReadCommand.array();
String res = new String(ar, 0, read); String res = new String(ar, 0, read);
readCommand += res; readCommand += res;
@ -205,11 +220,53 @@ public class OsMoThread {
} }
if (queueOfMessages.size() > 0) { if (queueOfMessages.size() > 0) {
processReadMessages();
}
}
private void processReadMessages() {
while(!queueOfMessages.isEmpty()){ while(!queueOfMessages.isEmpty()){
String cmd = queueOfMessages.poll(); String cmd = queueOfMessages.poll();
log.info("OSMO get:"+cmd);
int k = cmd.indexOf('|');
String header = cmd;
String data = "";
if(k >= 0) {
header = cmd.substring(0, k);
data = cmd.substring(k + 1);
}
JSONObject obj = null;
if(data.startsWith("{")) {
try {
obj = new JSONObject(data);
} catch (JSONException e) {
e.printStackTrace();
}
}
boolean error = false;
if(obj != null && obj.has("error")) {
error = true;
try {
service.showErrorMessage(obj.getString("error"));
} catch (JSONException e) {
e.printStackTrace();
}
}
if(header.equalsIgnoreCase("TOKEN")) {
if(!error){
authorized = 2;
try {
parseAuthCommand(data, obj);
} catch (JSONException e) {
service.showErrorMessage(e.getMessage());
}
}
continue;
}
boolean processed = false; boolean processed = false;
for (OsMoReactor o : listReactors) { for (OsMoReactor o : listReactors) {
if (o.acceptCommand(cmd)) { if (o.acceptCommand(header, data, obj, this)) {
processed = true; processed = true;
break; break;
} }
@ -220,30 +277,72 @@ public class OsMoThread {
} }
} }
private void parseAuthCommand(String data, JSONObject obj) throws JSONException {
if(sessionInfo != null) {
if(obj.has("protocol")) {
sessionInfo.protocol = obj.getString("protocol");
}
if(obj.has("now")) {
sessionInfo.serverTimeDelta = obj.getLong("now") - System.currentTimeMillis();
}
if(obj.has("name")) {
sessionInfo.username = obj.getString("name");
}
if (obj.has("motd")) {
sessionInfo.motdTimestamp = obj.getLong("motd");
}
if(obj.has("tracker_id")) {
sessionInfo.trackerId= obj.getString("tracker_id");
}
if(obj.has("group_tracker_id")) {
sessionInfo.groupTrackerId= obj.getString("group_tracker_id");
}
}
}
public long getConnectionTime() {
return connectionTime;
} }
private void writeCommands() throws UnsupportedEncodingException, IOException { private void writeCommands() throws UnsupportedEncodingException, IOException {
if (pendingSendCommand == null) { if (pendingSendCommand == null) {
getNewPendingSendCommand(); pendingSendCommand = getNewPendingSendCommand();
} }
while (pendingSendCommand != null) { while (pendingSendCommand != null) {
activeChannel.write(pendingSendCommand); activeChannel.write(pendingSendCommand);
if (!pendingSendCommand.hasRemaining()) { if (!pendingSendCommand.hasRemaining()) {
pendingSendCommand = null; pendingSendCommand = getNewPendingSendCommand();
getNewPendingSendCommand(); } else {
break;
} }
} }
} }
private void getNewPendingSendCommand() throws UnsupportedEncodingException {
private ByteBuffer getNewPendingSendCommand() throws UnsupportedEncodingException {
if(authorized == 0) {
String auth = "TOKEN|"+ sessionInfo.token;
log.info("OSMO send:" + auth);
authorized = 1;
return ByteBuffer.wrap(prepareCommand(auth).toString().getBytes("UTF-8"));
}
if(authorized == 1) {
return null;
}
for (OsMoSender s : listSenders) { for (OsMoSender s : listSenders) {
String l = s.nextSendCommand(); String l = s.nextSendCommand(this);
if (l != null) { if (l != null) {
StringBuilder res = prepareCommand(l); StringBuilder res = prepareCommand(l);
pendingSendCommand = ByteBuffer.wrap(res.toString().getBytes("UTF-8")); log.info("OSMO send " + res);
break; return ByteBuffer.wrap(res.toString().getBytes("UTF-8"));
} }
} }
return null;
}
public SessionInfo getSessionInfo() {
return sessionInfo;
} }
private StringBuilder prepareCommand(String l) { private StringBuilder prepareCommand(String l) {

View file

@ -1,19 +1,58 @@
package net.osmand.plus.osmo; package net.osmand.plus.osmo;
import java.util.LinkedList; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import net.osmand.Location; import net.osmand.Location;
import net.osmand.plus.osmo.OsMoService.OsMoSender; import net.osmand.plus.views.OsmandMapTileView;
public class OsMoTracker implements OsMoSender { import org.json.JSONObject;
private LinkedList<Location> bufferOfLocations = new LinkedList<Location>();
public class OsMoTracker implements OsMoSender, OsMoReactor {
private ConcurrentLinkedQueue<Location> bufferOfLocations = new ConcurrentLinkedQueue<Location>();
private Map<String, Location> otherLocations = new ConcurrentHashMap<String, Location>();
private boolean startSendingLocations;
private OsmandMapTileView view;
private OsMoService service;
private int locationsSent = 0;
public OsMoTracker(OsMoService service) { public OsMoTracker(OsMoService service) {
this.service = service;
service.registerSender(this); service.registerSender(this);
service.registerReactor(this);
}
public boolean isEnabledTracker() {
return startSendingLocations;
}
public void enableTracker() {
if(!startSendingLocations) {
startSendingLocations = true;
service.pushCommand("TRACKER_SESSION_OPEN");
}
}
public void disableTracker() {
if(startSendingLocations) {
startSendingLocations = false;
service.pushCommand("TRACKER_SESSION_CLOSE");
}
}
public void startTrackingId(String id) {
service.pushCommand("LISTEN|"+id);
otherLocations.put(id, null);
}
public void stopTrackingId(String id) {
service.pushCommand("UNLISTEN|"+id);
otherLocations.remove(id);
} }
@Override @Override
public String nextSendCommand() { public String nextSendCommand(OsMoThread thread) {
if(!bufferOfLocations.isEmpty()){ if(!bufferOfLocations.isEmpty()){
Location loc = bufferOfLocations.poll(); Location loc = bufferOfLocations.poll();
StringBuilder cmd = new StringBuilder("T|"); StringBuilder cmd = new StringBuilder("T|");
@ -27,14 +66,31 @@ public class OsMoTracker implements OsMoSender {
if(loc.hasSpeed()) { if(loc.hasSpeed()) {
cmd.append("S").append((float)loc.getSpeed()); cmd.append("S").append((float)loc.getSpeed());
} }
if(loc.hasBearing()) {
cmd.append("C").append((float)loc.getBearing());
}
if((System.currentTimeMillis() - loc.getTime()) > 30000 && loc.getTime() != 0) {
cmd.append("T").append(loc.getTime());
}
locationsSent ++;
return cmd.toString(); return cmd.toString();
} }
return null; return null;
} }
public void sendCoordinate(Location location) { public void sendCoordinate(Location location) {
if(startSendingLocations) {
bufferOfLocations.add(location); bufferOfLocations.add(location);
} }
}
public int getLocationsSent() {
return locationsSent;
}
public int getBufferLocationsSize() {
return bufferOfLocations.size();
}
public void sendCoordinate(double lat, double lon) { public void sendCoordinate(double lat, double lon) {
Location l = new Location("test"); Location l = new Location("test");
@ -43,5 +99,56 @@ public class OsMoTracker implements OsMoSender {
bufferOfLocations.add(l); bufferOfLocations.add(l);
} }
public void setView(OsmandMapTileView view) {
this.view = view;
}
public OsmandMapTileView getView() {
return view;
}
@Override
public boolean acceptCommand(String command, String data, JSONObject obj, OsMoThread thread) {
if(command.startsWith("LT:")) {
String tid = command.substring(command.indexOf(':') + 1);
float lat = 0;
float lon = 0;
float speed = 0;
int k = 0;
for (int i = 0; i <= data.length(); i++) {
boolean separator = i == data.length() || Character.isDigit(data.charAt(i)) || data.charAt(i) == ':'
|| data.charAt(i) == '.';
if (separator) {
char ch = data.charAt(k);
String vl = data.substring(k + 1, i);
if (ch == 'L') {
int l = vl.indexOf(":");
lat = Float.parseFloat(vl.substring(0, l));
lon = Float.parseFloat(vl.substring(l + 1));
} else if (ch == 'S') {
speed = Float.parseFloat(vl);
}
k = i;
}
}
if(lat != 0 || lon != 0) {
Location loc = new Location("osmo");
loc.setTime(System.currentTimeMillis());
loc.setLatitude(lat);
loc.setLongitude(lon);
if(speed > 0) {
loc.setSpeed(speed);
}
otherLocations.put(tid, loc);
OsmandMapTileView v = view;
if(v != null){
v.refreshMap();
}
}
return true;
}
return false;
}
} }

View file

@ -1,32 +1,121 @@
package net.osmand.plus.osmo; package net.osmand.plus.osmo;
import net.osmand.access.AccessibleToast;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R; import net.osmand.plus.R;
import net.osmand.plus.activities.SettingsBaseActivity; import net.osmand.plus.activities.SettingsBaseActivity;
import net.osmand.plus.osmo.OsMoService.SessionInfo;
import net.osmand.util.Algorithms;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
import android.provider.Settings; import android.text.format.DateFormat;
import android.util.TimeUtils;
import android.widget.ProgressBar;
import android.widget.Toast;
public class SettingsOsMoActivity extends SettingsBaseActivity { public class SettingsOsMoActivity extends SettingsBaseActivity {
public static final String MORE_VALUE = "MORE_VALUE"; public static final String MORE_VALUE = "MORE_VALUE";
public static final String DEFINE_EDIT = "DEFINE_EDIT"; public static final String DEFINE_EDIT = "DEFINE_EDIT";
private Preference debugPref;
private Preference trackerId;
private CheckBoxPreference sendLocationsref;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
getSupportActionBar().setTitle(R.string.online_map_settings); getSupportActionBar().setTitle(R.string.osmo_settings);
PreferenceScreen grp = getPreferenceScreen(); PreferenceScreen grp = getPreferenceScreen();
Preference pref = new Preference(this);
pref.setTitle(R.string.osmo_settings_uuid);
pref.setSummary(OsMoPlugin.getUUID(this));
grp.addPreference(pref);
trackerId = new Preference(this);
trackerId.setTitle(R.string.osmo_tracker_id);
trackerId.setSummary(R.string.osmo_tracker_id_descr);
trackerId.setOnPreferenceClickListener(this);
grp.addPreference(trackerId);
sendLocationsref = createCheckBoxPreference(settings.OSMO_AUTO_SEND_LOCATIONS);
sendLocationsref.setTitle(R.string.osmo_auto_send_locations);
sendLocationsref.setSummary(R.string.osmo_auto_send_locations_descr);
grp.addPreference(sendLocationsref);
debugPref = new Preference(this);
debugPref.setTitle(R.string.osmo_settings_debug);
debugPref.setOnPreferenceClickListener(this);
updateDebugPref();
grp.addPreference(debugPref);
}
private void updateDebugPref() {
final OsMoPlugin plugin = OsMoPlugin.getEnabledPlugin(OsMoPlugin.class);
OsMoService service = plugin.getService();
OsMoTracker tracker = plugin.getTracker();
StringBuilder s = new StringBuilder();
if(service.isConnected()) {
int seconds = (int) ((System.currentTimeMillis() - service.getConnectionTime()) / 1000);
s.append(getString(R.string.osmo_conn_successfull, Algorithms.formatDuration(seconds))).append("\n");
SessionInfo si = service.getCurrentSessionInfo();
if(si == null) {
s.append(getString(R.string.osmo_auth_pending)).append("\n");
} else {
s.append(getString(R.string.osmo_session_token, si.token)).append("\n");
}
} else {
String err = service.getLastRegistrationError();
if(err == null) {
err = "...";
}
s.append(getString(R.string.osmo_io_error) + err).append("\n");
}
s.append(getString(R.string.osmo_locations_sent,
tracker.getLocationsSent(),
tracker.getBufferLocationsSize())).append("\n");
s.append(getString(R.string.osmo_settings_uuid)).append(" : ")
.append(getMyApplication().getSettings().OSMO_DEVICE_KEY.get().toUpperCase()).append("\n");
debugPref.setSummary(s.toString().trim());
}
@Override
public boolean onPreferenceClick(Preference preference) {
if (preference == debugPref) {
updateDebugPref();
return true;
} else if(preference == trackerId) {
final OsMoPlugin plugin = OsMoPlugin.getEnabledPlugin(OsMoPlugin.class);
OsMoService service = plugin.getService();
SessionInfo ci = service.getCurrentSessionInfo();
if(ci == null || ci.trackerId == null) {
AccessibleToast.makeText(this, R.string.osmo_auth_pending, Toast.LENGTH_SHORT).show();
} else {
Builder bld = new AlertDialog.Builder(this);
bld.setTitle(R.string.osmo_tracker_id);
bld.setMessage(ci.trackerId);
bld.show();
}
}
return super.onPreferenceClick(preference);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean p = super.onPreferenceChange(preference, newValue);
String id = preference.getKey();
if (id.equals(settings.OSMO_AUTO_SEND_LOCATIONS.getId())) {
if ((Boolean) newValue) {
final OsMoPlugin plugin = OsMoPlugin.getEnabledPlugin(OsMoPlugin.class);
plugin.getTracker().enableTracker();
}
}
return p;
} }

View file

@ -119,7 +119,8 @@ public class RouteProvider {
private boolean reverse; private boolean reverse;
private boolean leftSide; private boolean leftSide;
private boolean passWholeRoute; private boolean passWholeRoute;
public boolean calculateOsmAndRouteParts; private boolean calculateOsmAndRouteParts;
private boolean useIntermediatePointsRTE;
public GPXRouteParamsBuilder(GPXFile file, OsmandSettings settings){ public GPXRouteParamsBuilder(GPXFile file, OsmandSettings settings){
leftSide = settings.DRIVING_REGION.get().leftHandDriving; leftSide = settings.DRIVING_REGION.get().leftHandDriving;
@ -142,6 +143,14 @@ public class RouteProvider {
this.calculateOsmAndRouteParts = calculateOsmAndRouteParts; this.calculateOsmAndRouteParts = calculateOsmAndRouteParts;
} }
public void setUseIntermediatePointsRTE(boolean useIntermediatePointsRTE) {
this.useIntermediatePointsRTE = useIntermediatePointsRTE;
}
public boolean isUseIntermediatePointsRTE() {
return useIntermediatePointsRTE;
}
public boolean isCalculateOsmAndRoute() { public boolean isCalculateOsmAndRoute() {
return calculateOsmAndRoute; return calculateOsmAndRoute;
} }
@ -196,6 +205,7 @@ public class RouteProvider {
boolean calculateOsmAndRoute; boolean calculateOsmAndRoute;
boolean passWholeRoute; boolean passWholeRoute;
boolean calculateOsmAndRouteParts; boolean calculateOsmAndRouteParts;
boolean useIntermediatePointsRTE;
public List<Location> getPoints() { public List<Location> getPoints() {
return points; return points;
@ -229,8 +239,9 @@ public class RouteProvider {
boolean reverse = builder.reverse; boolean reverse = builder.reverse;
passWholeRoute = builder.passWholeRoute; passWholeRoute = builder.passWholeRoute;
calculateOsmAndRouteParts = builder.calculateOsmAndRouteParts; calculateOsmAndRouteParts = builder.calculateOsmAndRouteParts;
useIntermediatePointsRTE = builder.useIntermediatePointsRTE;
boolean announceWaypoints = builder.announceWaypoints; boolean announceWaypoints = builder.announceWaypoints;
calculateOsmAndRoute = false; // Disabled temporary builder.calculateOsmAndRoute; builder.calculateOsmAndRoute = false; // Disabled temporary builder.calculateOsmAndRoute;
if(file.isCloudmadeRouteFile() || OSMAND_ROUTER.equals(file.author)){ if(file.isCloudmadeRouteFile() || OSMAND_ROUTER.equals(file.author)){
directions = parseOsmAndGPXRoute(points, file, OSMAND_ROUTER.equals(file.author), builder.leftSide, 10); directions = parseOsmAndGPXRoute(points, file, OSMAND_ROUTER.equals(file.author), builder.leftSide, 10);
if(reverse){ if(reverse){
@ -240,6 +251,7 @@ public class RouteProvider {
} }
} else { } else {
// first of all check tracks // first of all check tracks
if (!useIntermediatePointsRTE) {
for (Track tr : file.tracks) { for (Track tr : file.tracks) {
for (TrkSegment tkSeg : tr.segments) { for (TrkSegment tkSeg : tr.segments) {
for (WptPt pt : tkSeg.points) { for (WptPt pt : tkSeg.points) {
@ -247,6 +259,7 @@ public class RouteProvider {
} }
} }
} }
}
if (points.isEmpty()) { if (points.isEmpty()) {
for (Route rte : file.routes) { for (Route rte : file.routes) {
for (WptPt pt : rte.points) { for (WptPt pt : rte.points) {
@ -348,9 +361,13 @@ public class RouteProvider {
return res; return res;
} }
private RouteCalculationResult calculateGpxRoute(RouteCalculationParams routeParams) { private RouteCalculationResult calculateGpxRoute(RouteCalculationParams routeParams) throws IOException {
// get the closest point to start and to end // get the closest point to start and to end
GPXRouteParams gpxParams = routeParams.gpxRoute; GPXRouteParams gpxParams = routeParams.gpxRoute;
if(routeParams.gpxRoute.useIntermediatePointsRTE){
final List<Location> intermediates = gpxParams.points;
return calculateOsmAndRouteWithIntermediatePoints(routeParams, intermediates);
}
List<Location> gpxRoute ; List<Location> gpxRoute ;
int[] startI = new int[]{0}; int[] startI = new int[]{0};
int[] endI = new int[]{gpxParams.points.size()}; int[] endI = new int[]{gpxParams.points.size()};
@ -378,6 +395,28 @@ public class RouteProvider {
private RouteCalculationResult calculateOsmAndRouteWithIntermediatePoints(RouteCalculationParams routeParams,
final List<Location> intermediates) throws IOException {
RouteCalculationParams rp = new RouteCalculationParams();
rp.calculationProgress = routeParams.calculationProgress;
rp.ctx = routeParams.ctx;
rp.mode = routeParams.mode;
rp.start = routeParams.start;
rp.end = routeParams.end;
rp.leftSide = routeParams.leftSide;
rp.type = routeParams.type;
rp.fast = routeParams.fast;
rp.previousToRecalculate = routeParams.previousToRecalculate;
rp.intermediates = new ArrayList<LatLon>();
for(Location w : intermediates) {
rp.intermediates.add(new LatLon(w.getLatitude(), w.getLongitude()));
}
return findVectorMapsRoute(rp, false);
}
private List<RouteDirectionInfo> calcDirections(int[] startI, int[] endI, private List<RouteDirectionInfo> calcDirections(int[] startI, int[] endI,
final List<RouteDirectionInfo> inputDirections) { final List<RouteDirectionInfo> inputDirections) {
List<RouteDirectionInfo> directions = new ArrayList<RouteDirectionInfo>(); List<RouteDirectionInfo> directions = new ArrayList<RouteDirectionInfo>();

View file

@ -757,7 +757,7 @@ public class RoutingHelper {
return; return;
} }
final boolean onlineSourceWithoutInternet = !res.isCalculated() && params.type.isOnline() && !settings.isInternetConnectionAvailable(); final boolean onlineSourceWithoutInternet = !res.isCalculated() && params.type.isOnline() && !settings.isInternetConnectionAvailable();
if (onlineSourceWithoutInternet && settings.ROUTE_CALC_OSMAND_PARTS.get()) { if (onlineSourceWithoutInternet && settings.GPX_ROUTE_CALC_OSMAND_PARTS.get()) {
if (params.previousToRecalculate != null && params.previousToRecalculate.isCalculated()) { if (params.previousToRecalculate != null && params.previousToRecalculate.isCalculated()) {
res = provider.recalculatePartOfflineRoute(res, params); res = provider.recalculatePartOfflineRoute(res, params);
} }

View file

@ -188,20 +188,23 @@ public class MapRoutePreferencesControl extends MapControls {
} }
} else if (gpxParam.id == R.string.gpx_option_calculate_first_last_segment) { } else if (gpxParam.id == R.string.gpx_option_calculate_first_last_segment) {
rp.setCalculateOsmAndRouteParts(selected); rp.setCalculateOsmAndRouteParts(selected);
settings.ROUTE_CALC_OSMAND_PARTS.set(selected); settings.GPX_ROUTE_CALC_OSMAND_PARTS.set(selected);
} else if (gpxParam.id == R.string.gpx_option_from_start_point) { } else if (gpxParam.id == R.string.gpx_option_from_start_point) {
rp.setPassWholeRoute(selected); rp.setPassWholeRoute(selected);
} else if (gpxParam.id == R.string.announce_gpx_waypoints) { } else if (gpxParam.id == R.string.announce_gpx_waypoints) {
settings.SPEAK_GPX_WPT.set(selected); settings.GPX_SPEAK_WPT.set(selected);
rp.setAnnounceWaypoints(selected); rp.setAnnounceWaypoints(selected);
} else if (gpxParam.id == R.string.use_points_as_intermediates) {
settings.GPX_CALCULATE_RTEPT.set(selected);
rp.setUseIntermediatePointsRTE(selected);
} else if (gpxParam.id == R.string.calculate_osmand_route_gpx) { } else if (gpxParam.id == R.string.calculate_osmand_route_gpx) {
settings.CALC_GPX_ROUTE.set(selected); settings.GPX_ROUTE_CALC.set(selected);
rp.setCalculateOsmAndRoute(selected); rp.setCalculateOsmAndRoute(selected);
updateParameters(); updateParameters();
} }
} }
if (gpxParam.id == R.string.calculate_osmand_route_without_internet) { if (gpxParam.id == R.string.calculate_osmand_route_without_internet) {
settings.ROUTE_CALC_OSMAND_PARTS.set(selected); settings.GPX_ROUTE_CALC_OSMAND_PARTS.set(selected);
} }
if (gpxParam.id == R.string.fast_route_mode) { if (gpxParam.id == R.string.fast_route_mode) {
settings.FAST_ROUTE_MODE.set(selected); settings.FAST_ROUTE_MODE.set(selected);
@ -215,18 +218,25 @@ public class MapRoutePreferencesControl extends MapControls {
boolean osmandRouter = settings.ROUTER_SERVICE.get() == RouteService.OSMAND ; boolean osmandRouter = settings.ROUTER_SERVICE.get() == RouteService.OSMAND ;
if(!osmandRouter) { if(!osmandRouter) {
list.add(new OtherLocalRoutingParameter(R.string.calculate_osmand_route_without_internet, list.add(new OtherLocalRoutingParameter(R.string.calculate_osmand_route_without_internet,
getString(R.string.calculate_osmand_route_without_internet), settings.ROUTE_CALC_OSMAND_PARTS.get())); getString(R.string.calculate_osmand_route_without_internet), settings.GPX_ROUTE_CALC_OSMAND_PARTS.get()));
list.add(new OtherLocalRoutingParameter(R.string.fast_route_mode, list.add(new OtherLocalRoutingParameter(R.string.fast_route_mode,
getString(R.string.fast_route_mode), settings.FAST_ROUTE_MODE.get())); getString(R.string.fast_route_mode), settings.FAST_ROUTE_MODE.get()));
return list; return list;
} }
if(rparams != null) { if(rparams != null) {
GPXFile fl = rparams.getFile();
if (fl.hasRtePt()) {
list.add(new OtherLocalRoutingParameter(R.string.use_points_as_intermediates,
getString(R.string.use_points_as_intermediates), rparams.isUseIntermediatePointsRTE()));
}
list.add(new OtherLocalRoutingParameter(R.string.gpx_option_reverse_route, list.add(new OtherLocalRoutingParameter(R.string.gpx_option_reverse_route,
getString(R.string.gpx_option_reverse_route), rparams.isReverse())); getString(R.string.gpx_option_reverse_route), rparams.isReverse()));
if (!rparams.isUseIntermediatePointsRTE()) {
list.add(new OtherLocalRoutingParameter(R.string.gpx_option_from_start_point, list.add(new OtherLocalRoutingParameter(R.string.gpx_option_from_start_point,
getString(R.string.gpx_option_from_start_point), rparams.isPassWholeRoute())); getString(R.string.gpx_option_from_start_point), rparams.isPassWholeRoute()));
list.add(new OtherLocalRoutingParameter(R.string.gpx_option_calculate_first_last_segment, list.add(new OtherLocalRoutingParameter(R.string.gpx_option_calculate_first_last_segment,
getString(R.string.gpx_option_calculate_first_last_segment), rparams.isCalculateOsmAndRouteParts())); getString(R.string.gpx_option_calculate_first_last_segment), rparams.isCalculateOsmAndRouteParts()));
}
list.add(new OtherLocalRoutingParameter(R.string.announce_gpx_waypoints, list.add(new OtherLocalRoutingParameter(R.string.announce_gpx_waypoints,
getString(R.string.announce_gpx_waypoints), rparams.isAnnounceWaypoints())); getString(R.string.announce_gpx_waypoints), rparams.isAnnounceWaypoints()));
// Temporary disabled // Temporary disabled