diff --git a/DataExtractionOSM/src/com/osmand/ToDoConstants.java b/DataExtractionOSM/src/com/osmand/ToDoConstants.java index 92ec1e61af..13efd7ad8f 100644 --- a/DataExtractionOSM/src/com/osmand/ToDoConstants.java +++ b/DataExtractionOSM/src/com/osmand/ToDoConstants.java @@ -18,30 +18,28 @@ public class ToDoConstants { // 42. Revise UI (icons/layouts). Support different devices. Add inactive/focus(!) icon versions. // Some icons are not fine (as back menu from map - it is blured). // Got by Andrei - // 50. Invent opening hours editor in order to edit POI hours better on device // GOT by Olga // 60. Audio guidance for routing - // 61. Provide route information for YOURS (calclate turns/angle/expected time) - // 58. Upload/Download zip-index from site & unzip them on phone - // 53. Add progress bars : to internet communication activities [editing/commiting/deleting poi], do not hide edit poi dialog if operation failed - // [move close buttons from alertdialog to own view] + // 61. Provide route information for YOURS (calclate turns/angle/expected time). + // Fix some missing turns in CloudMade (for secondary roads wo name). Add them (if dist to prev/next turn > 150m) // 55. Update POI data from internet for selected area [suggest to create new POI index or extend exising of none exist] + + // 43. Enable poi filter by name + // 58. Upload/Download zip-index from site & unzip them on phone // 45. Get clear settings. Move that setting on top settings screen. // That setting should rule all activities that use internet. It should ask whenever internet is used // (would you like to use internet for that operation - if using internet is not checked). // Internet using now for : edit POI osm, show osm bugs layer, download tiles. - // 33. Build transport locations. Create transport index (transport-stops) (investigate) // DONE: Load transport routes in swing. - // IDEA TO HAVE : - // 47. Internet connectivity could be checked before trying to use (?) - // 40. Support simple vector road rendering (require new index file) (?) - // 26. Show the whole street on map (when it is chosen in search activity). Possibly extend that story to show layer with streets. (?) + // IDEA TO HAVE : + + // 40. Support simple vector road rendering (require new index file) (?) + // 63. Support simple offline routing(require new index file) (?) - // BUGS Android // TODO swing @@ -53,7 +51,13 @@ public class ToDoConstants { // BUGS Swing - // DONE ANDROID : + // DONE ANDROID : + // 62. History of searched points (once point was selected to go/to show it is saved in history db and could be shown) + // 47. Internet connectivity could be checked before trying to use [merged with 45] + // 26. Show the whole street on map (when it is chosen in search activity). Possibly extend that story to show layer with streets. + // [Closed : because it is not necessary] + // 53. Add progress bars : to internet communication activities [editing/commiting/deleting poi], do not hide edit poi dialog if operation failed + // 63. Implement internet search address [OSM Nominatim] // 56. Add usage of CloudMade API for calculating route (show next turn & distance to it instead of mini map). // 57. Implement routing information about expected time arriving // 58. Implement difference about show route/follow route (show travel time/arrival time, show mini map/next turn, etc) diff --git a/OsmAnd/AndroidManifest.xml b/OsmAnd/AndroidManifest.xml index 5fa3bce80f..f1f33fc4e5 100644 --- a/OsmAnd/AndroidManifest.xml +++ b/OsmAnd/AndroidManifest.xml @@ -20,7 +20,9 @@ + + diff --git a/OsmAnd/res/layout/search_address.xml b/OsmAnd/res/layout/search_address.xml index 127fed05e1..7632706571 100644 --- a/OsmAnd/res/layout/search_address.xml +++ b/OsmAnd/res/layout/search_address.xml @@ -8,7 +8,7 @@ - + @@ -49,18 +49,27 @@ - - - - - - + - + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/search_address_online.xml b/OsmAnd/res/layout/search_address_online.xml new file mode 100644 index 0000000000..1409acc139 --- /dev/null +++ b/OsmAnd/res/layout/search_address_online.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + diff --git a/OsmAnd/res/layout/search_address_online_list_item.xml b/OsmAnd/res/layout/search_address_online_list_item.xml new file mode 100644 index 0000000000..36a13a9494 --- /dev/null +++ b/OsmAnd/res/layout/search_address_online_list_item.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/OsmAnd/res/layout/search_history_list_item.xml b/OsmAnd/res/layout/search_history_list_item.xml new file mode 100644 index 0000000000..433f4a9f2f --- /dev/null +++ b/OsmAnd/res/layout/search_history_list_item.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/OsmAnd/res/values-ru-rRU/strings.xml b/OsmAnd/res/values-ru-rRU/strings.xml index b8348d6bde..6c72c44a94 100644 --- a/OsmAnd/res/values-ru-rRU/strings.xml +++ b/OsmAnd/res/values-ru-rRU/strings.xml @@ -1,5 +1,16 @@ + Очистить все + История + Загрузка данных... + Загрузка + По вашему запросу ничего не найдено + Поиск + Поиск адреса... + Поиск адреса используя Osm Nominatim + Город, улица, дом + Локальный + Интернет Уровень детализация Выберите максимальный уровень для загрузки из интернета О маршруте @@ -35,7 +46,7 @@ Сохранения объекта Загрузка poi Авторизация не прошла - , ошибка : + , ошибка Конвертация имен английский/родных... Загружаются дома/улицы... Загружаются почтовые индексы... @@ -47,7 +58,7 @@ Ошибка прокладки маршрута: Ошибка во время прокладки маршрута Пустой путь рассчитан - Проложен новый путь, расстояние : + Проложен новый путь, расстояние : Вы прибыли в пункт назначения Координаты неправильные Вернуться к OsmAnd карте @@ -115,7 +126,7 @@ Вращать карту Показывать слой POI POI - Загружать недостающие части карты из: + Загружать недостающие части карты из : Источник данных Источник карты Интернет @@ -217,8 +228,8 @@ Удаление POI Удалить POI был успешно удален. -Дабавить -Изменить +добавления +изменения Действие {0} успешно завершено. Неожиданная ошибка произошла при выполнении действия {0}. Ошибка ввода/вывода произошла при выполнении действия {0}. diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 96c403114e..eaf82e5a4d 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -1,5 +1,22 @@ + City : {0} + Street : {0}, {1} + Intersection streets : {0} x {1} in {2} + Building : {0}, {1}, {2} + Navigate to lat = {0}, lon = {1} + Favorite + Clear all + History + Uploading data... + Uploading + Nothing was found + Searching + Searching address... + Search address using Osm Nominatim + House number, street, city + Offline + Internet Max zoom level Choose max zoom level to download using internet About route @@ -35,7 +52,7 @@ See osmand.googlecode.com. Commiting node Loading poi Authorization failed - failed : + failed Converting native/english names... Loading streets/buildings... Loading postcodes... @@ -47,7 +64,7 @@ See osmand.googlecode.com. Error calculating route : Error occurred while calculating route Empty route is calculated - New route is calculated, distance : + New route is calculated, distance : You arrived at destination point Locations are invalid Go back to OsmAnd map @@ -115,7 +132,7 @@ See osmand.googlecode.com. Rotate map Show POI over map (use last chosen filter) Show POI - Choose the source of tiles: + Choose the source of tiles : Map tile source Map source Use internet @@ -218,8 +235,8 @@ See osmand.googlecode.com. Delete POI Delete POI was successfully deleted -Add -Change +add +change Action {0} completed successfully. Unexpected error occured while performing action {0}. Input/output error occured while performing action {0}. diff --git a/OsmAnd/src/com/osmand/OsmandSettings.java b/OsmAnd/src/com/osmand/OsmandSettings.java index 57a55bff11..a651c095f1 100644 --- a/OsmAnd/src/com/osmand/OsmandSettings.java +++ b/OsmAnd/src/com/osmand/OsmandSettings.java @@ -7,6 +7,7 @@ import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import com.osmand.activities.RouteProvider.RouteService; +import com.osmand.activities.search.SearchHistoryHelper; import com.osmand.map.ITileSource; import com.osmand.map.TileSourceManager; import com.osmand.map.TileSourceManager.TileSourceTemplate; @@ -260,12 +261,19 @@ public class OsmandSettings { } public static void setMapLocationToShow(Context ctx, double latitude, double longitude) { + setMapLocationToShow(ctx, latitude, longitude, null); + } + + public static void setMapLocationToShow(Context ctx, double latitude, double longitude, String historyDescription) { SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE); Editor edit = prefs.edit(); edit.putFloat(LAST_KNOWN_MAP_LAT, (float) latitude); edit.putFloat(LAST_KNOWN_MAP_LON, (float) longitude); edit.putBoolean(IS_MAP_SYNC_TO_GPS_LOCATION, false); edit.commit(); + if(historyDescription != null){ + SearchHistoryHelper.getInstance().addNewItemToHistory(latitude, longitude, historyDescription, ctx); + } } // Do not use that method if you want to show point on map. Use setMapLocationToShow diff --git a/OsmAnd/src/com/osmand/PoiFiltersHelper.java b/OsmAnd/src/com/osmand/PoiFiltersHelper.java index 1f0f2a380b..9703075346 100644 --- a/OsmAnd/src/com/osmand/PoiFiltersHelper.java +++ b/OsmAnd/src/com/osmand/PoiFiltersHelper.java @@ -116,6 +116,10 @@ public class PoiFiltersHelper { return Collections.unmodifiableList(cacheUserDefinedFilters); } + public static String getOsmDefinedFilterId(AmenityType t){ + return PoiFilter.STD_PREFIX + t; + } + private static List cacheOsmDefinedFilters; public static List getOsmDefinedPoiFilters(Context ctx){ if(cacheOsmDefinedFilters == null){ diff --git a/OsmAnd/src/com/osmand/activities/EditingPOIActivity.java b/OsmAnd/src/com/osmand/activities/EditingPOIActivity.java index abe3c72775..aee0bc8c12 100644 --- a/OsmAnd/src/com/osmand/activities/EditingPOIActivity.java +++ b/OsmAnd/src/com/osmand/activities/EditingPOIActivity.java @@ -33,6 +33,7 @@ import org.xmlpull.v1.XmlSerializer; import android.app.AlertDialog; import android.app.Dialog; +import android.app.ProgressDialog; import android.app.AlertDialog.Builder; import android.content.Context; import android.content.DialogInterface; @@ -81,11 +82,6 @@ public class EditingPOIActivity { private EditText commentText; private final static Log log = LogUtil.getLog(EditingPOIActivity.class); - public EditingPOIActivity(final Context ctx){ - this.ctx = ctx; - this.view = null; - } - public EditingPOIActivity(final Context ctx, OsmandMapTileView view){ this.ctx = ctx; @@ -127,12 +123,15 @@ public class EditingPOIActivity { @Override public void onClick(DialogInterface dialog, int which) { String c = comment.getText().toString(); - if(commitNode(DELETE_ACTION, n, entityInfo, c)){ // NON-NLS - Toast.makeText(ctx, ctx.getResources().getString(R.string.poi_remove_success), Toast.LENGTH_LONG).show(); - if(view != null){ - view.refreshMap(); + commitNode(DELETE_ACTION, n, entityInfo, c, new Runnable(){ + @Override + public void run() { + Toast.makeText(ctx, ctx.getResources().getString(R.string.poi_remove_success), Toast.LENGTH_LONG).show(); + if(view != null){ + view.refreshMap(); + } } - } + }); } }); builder.show(); @@ -186,22 +185,28 @@ public class EditingPOIActivity { @Override public void onClick(View v) { Resources resources = v.getResources(); - String msg = n.getId() == -1 ? resources.getString(R.string.poi_action_add) : resources.getString(R.string.poi_action_change); - String action = n.getId() == -1 ? CREATE_ACTION: MODIFY_ACTION; + final String msg = n.getId() == -1 ? resources.getString(R.string.poi_action_add) : resources + .getString(R.string.poi_action_change); + String action = n.getId() == -1 ? CREATE_ACTION : MODIFY_ACTION; n.putTag(a.convertToAmenityTag(), typeText.getText().toString()); n.putTag(OSMTagKey.NAME.getValue(), nameText.getText().toString()); - if(openingHours.getText().toString().length() == 0){ + if (openingHours.getText().toString().length() == 0) { n.removeTag(OSMTagKey.OPENING_HOURS.getValue()); - } else { + } else { n.putTag(OSMTagKey.OPENING_HOURS.getValue(), openingHours.getText().toString()); - } - if (commitNode(action, n, entityInfo, commentText.getText().toString())) { - Toast.makeText(ctx, MessageFormat.format(ctx.getResources().getString(R.string.poi_action_succeded_template), msg), Toast.LENGTH_LONG).show(); - if(view != null){ - view.refreshMap(); - } } - dlg.dismiss(); + commitNode(action, n, entityInfo, commentText.getText().toString(), new Runnable() { + @Override + public void run() { + Toast.makeText(ctx, MessageFormat.format(ctx.getResources().getString(R.string.poi_action_succeded_template), msg), + Toast.LENGTH_LONG).show(); + if (view != null) { + view.refreshMap(); + } + dlg.dismiss(); + + } + }); } }); @@ -218,6 +223,16 @@ public class EditingPOIActivity { typeText.setAdapter(adapter); } + private void showWarning(final String msg){ + view.post(new Runnable(){ + @Override + public void run() { + Toast.makeText(ctx, msg, Toast.LENGTH_LONG).show(); + } + + }); + } + @@ -266,13 +281,13 @@ public class EditingPOIActivity { String msg; if(response.getStatusLine() != null){ - msg = userOperation + " failed" ; //$NON-NLS-1$ + msg = userOperation + " " +ctx.getString(R.string.failed_op); //$NON-NLS-1$ } else { - msg = userOperation + " failed " + response.getStatusLine().getStatusCode() +" : "+ //$NON-NLS-1$//$NON-NLS-2$ + msg = userOperation + " " + ctx.getString(R.string.failed_op) + response.getStatusLine().getStatusCode() + " : " + //$NON-NLS-1$//$NON-NLS-2$ response.getStatusLine().getReasonPhrase(); } log.error(msg); - Toast.makeText(ctx, msg, Toast.LENGTH_LONG).show(); + showWarning(msg); } else { InputStream is = response.getEntity().getContent(); if (is != null) { @@ -289,10 +304,10 @@ public class EditingPOIActivity { } } catch (MalformedURLException e) { log.error(userOperation + " failed", e); //$NON-NLS-1$ - Toast.makeText(ctx, MessageFormat.format(ctx.getResources().getString(R.string.poi_error_unexpected_template), userOperation), Toast.LENGTH_LONG).show(); + showWarning(MessageFormat.format(ctx.getResources().getString(R.string.poi_error_unexpected_template), userOperation)); } catch (IOException e) { log.error(userOperation + " failed", e); //$NON-NLS-1$ - Toast.makeText(ctx, MessageFormat.format(ctx.getResources().getString(R.string.poi_error_unexpected_template), userOperation), Toast.LENGTH_LONG).show(); + showWarning(MessageFormat.format(ctx.getResources().getString(R.string.poi_error_unexpected_template), userOperation)); } return null; @@ -327,9 +342,9 @@ public class EditingPOIActivity { } connection.connect(); if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { - String msg = userOperation + ctx.getString(R.string.failed_op) + connection.getResponseMessage(); + String msg = userOperation + " " + ctx.getString(R.string.failed_op) + " : " + connection.getResponseMessage(); //$NON-NLS-1$//$NON-NLS-2$ log.error(msg); - Toast.makeText(ctx, msg, Toast.LENGTH_LONG).show(); + showWarning(msg); } else { log.info("Response : " + connection.getResponseMessage()); //$NON-NLS-1$ // populate return fields. @@ -354,13 +369,13 @@ public class EditingPOIActivity { // that's tricky case why NPE is thrown to fix that problem httpClient could be used String msg = ctx.getString(R.string.auth_failed); log.error(msg , e); - Toast.makeText(ctx, msg, Toast.LENGTH_LONG).show(); + showWarning(msg); } catch (MalformedURLException e) { - log.error(userOperation + ctx.getString(R.string.failed_op) , e); - Toast.makeText(ctx, MessageFormat.format(ctx.getResources().getString(R.string.poi_error_unexpected_template), userOperation), Toast.LENGTH_LONG).show(); + log.error(userOperation + " " + ctx.getString(R.string.failed_op) , e); //$NON-NLS-1$ + showWarning(MessageFormat.format(ctx.getResources().getString(R.string.poi_error_unexpected_template), userOperation)); } catch (IOException e) { - log.error(userOperation + ctx.getString(R.string.failed_op) , e); - Toast.makeText(ctx, MessageFormat.format(ctx.getResources().getString(R.string.poi_error_io_error_template), userOperation), Toast.LENGTH_LONG).show(); + log.error(userOperation + " " + ctx.getString(R.string.failed_op) , e); //$NON-NLS-1$ + showWarning(MessageFormat.format(ctx.getResources().getString(R.string.poi_error_io_error_template), userOperation)); } return null; @@ -451,12 +466,30 @@ public class EditingPOIActivity { } - public boolean commitNode(String action, Node n, EntityInfo info, String comment){ - if(info == null && !CREATE_ACTION.equals(action)){ + + public void commitNode(final String action, final Node n, final EntityInfo info, final String comment, final Runnable successAction) { + if (info == null && !CREATE_ACTION.equals(action)) { Toast.makeText(ctx, ctx.getResources().getString(R.string.poi_error_info_not_loaded), Toast.LENGTH_LONG).show(); - return false; + return; } - + final ProgressDialog progress = ProgressDialog.show(ctx, ctx.getString(R.string.uploading), ctx.getString(R.string.uploading_data)); + new Thread(new Runnable() { + + @Override + public void run() { + try { + if (commitNodeImpl(action, n, info, comment)) { + view.post(successAction); + } + } finally { + progress.dismiss(); + } + + } + }, "EditingPoi").start(); //$NON-NLS-1$ + } + + public boolean commitNodeImpl(String action, Node n, EntityInfo info, String comment){ long changeSetId = openChangeSet(comment, n.getLatitude(), n.getLongitude()); if(changeSetId < 0){ return false; diff --git a/OsmAnd/src/com/osmand/activities/FavouritesActivity.java b/OsmAnd/src/com/osmand/activities/FavouritesActivity.java index ea53233b55..c0e36d7539 100644 --- a/OsmAnd/src/com/osmand/activities/FavouritesActivity.java +++ b/OsmAnd/src/com/osmand/activities/FavouritesActivity.java @@ -79,7 +79,7 @@ public class FavouritesActivity extends ListActivity { public void onListItemClick(ListView parent, View v, int position, long id) { FavouritePoint point = favouritesList.get(position); - OsmandSettings.setMapLocationToShow(this, point.getLatitude(), point.getLongitude()); + OsmandSettings.setMapLocationToShow(this, point.getLatitude(), point.getLongitude(), getString(R.string.favorite)+" : " + point.getName()); //$NON-NLS-1$ Intent newIntent = new Intent(FavouritesActivity.this, MapActivity.class); startActivity(newIntent); } @@ -89,7 +89,7 @@ public class FavouritesActivity extends ListActivity { AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) aItem.getMenuInfo(); final FavouritePoint point = (FavouritePoint) favouritesList.get(menuInfo.position); if(aItem.getItemId() == NAVIGATE_TO){ - OsmandSettings.setMapLocationToShow(this, point.getLatitude(), point.getLongitude()); + OsmandSettings.setMapLocationToShow(this, point.getLatitude(), point.getLongitude(), getString(R.string.favorite)+" : " + point.getName()); //$NON-NLS-1$ OsmandSettings.setPointToNavigate(this, point.getLatitude(), point.getLongitude()); Intent newIntent = new Intent(FavouritesActivity.this, MapActivity.class); startActivity(newIntent); diff --git a/OsmAnd/src/com/osmand/activities/MapActivity.java b/OsmAnd/src/com/osmand/activities/MapActivity.java index 68a365786f..f79ac16a91 100644 --- a/OsmAnd/src/com/osmand/activities/MapActivity.java +++ b/OsmAnd/src/com/osmand/activities/MapActivity.java @@ -742,7 +742,7 @@ public class MapActivity extends Activity implements LocationListener, IMapLocat } else if(which == 2){ osmBugsLayer.openBug(MapActivity.this, getLayoutInflater(), mapView, latitude, longitude); } else if(which == 3){ - EditingPOIActivity activity = new EditingPOIActivity(MapActivity.this); + EditingPOIActivity activity = new EditingPOIActivity(MapActivity.this, mapView); activity.showCreateDialog(latitude, longitude); } else if(which == 4){ reloadTile(mapView.getZoom(), latitude, longitude); diff --git a/OsmAnd/src/com/osmand/activities/NavigatePointActivity.java b/OsmAnd/src/com/osmand/activities/NavigatePointActivity.java index 68c253dee5..d79b9007f7 100644 --- a/OsmAnd/src/com/osmand/activities/NavigatePointActivity.java +++ b/OsmAnd/src/com/osmand/activities/NavigatePointActivity.java @@ -2,6 +2,7 @@ package com.osmand.activities; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; +import java.text.MessageFormat; import java.util.Locale; import android.app.Activity; @@ -125,7 +126,7 @@ public class NavigatePointActivity extends Activity { if(activity != null) { activity.setMapLocation(lat, lon); } else { - OsmandSettings.setMapLocationToShow(this, lat, lon); + OsmandSettings.setMapLocationToShow(this, lat, lon, MessageFormat.format(getString(R.string.search_history_navigate_to), lat, lon)); } if(navigate){ OsmandSettings.setPointToNavigate(this, lat, lon); diff --git a/OsmAnd/src/com/osmand/activities/SettingsActivity.java b/OsmAnd/src/com/osmand/activities/SettingsActivity.java index 3a468734ed..3e61293f11 100644 --- a/OsmAnd/src/com/osmand/activities/SettingsActivity.java +++ b/OsmAnd/src/com/osmand/activities/SettingsActivity.java @@ -20,6 +20,7 @@ import android.preference.Preference.OnPreferenceClickListener; import android.widget.Toast; import com.osmand.OsmandSettings; +import com.osmand.PoiFiltersHelper; import com.osmand.ProgressDialogImplementation; import com.osmand.R; import com.osmand.ResourceManager; @@ -202,6 +203,9 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference edit.commit(); } else if(preference == showPoiOnMap){ edit.putBoolean(OsmandSettings.SHOW_POI_OVER_MAP, (Boolean) newValue); + if((Boolean)newValue){ + edit.putString(OsmandSettings.SELECTED_POI_FILTER_FOR_MAP, PoiFiltersHelper.getOsmDefinedFilterId(null)); + } edit.commit(); } else if(preference == useInternetToDownloadTiles){ edit.putBoolean(OsmandSettings.USE_INTERNET_TO_DOWNLOAD_TILES, (Boolean) newValue); diff --git a/OsmAnd/src/com/osmand/activities/search/SearchActivity.java b/OsmAnd/src/com/osmand/activities/search/SearchActivity.java index b3faa4cff6..b37679be6c 100644 --- a/OsmAnd/src/com/osmand/activities/search/SearchActivity.java +++ b/OsmAnd/src/com/osmand/activities/search/SearchActivity.java @@ -11,6 +11,7 @@ import android.content.Intent; import android.os.Bundle; import android.widget.Button; import android.widget.TabHost; +import android.widget.TabHost.TabSpec; /** * @author Maxim Frolov @@ -19,14 +20,29 @@ import android.widget.TabHost; public class SearchActivity extends TabActivity { Button searchPOIButton; + private TabSpec addressSpec; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TabHost host = getTabHost(); host.addTab(host.newTabSpec("Search_POI").setIndicator(getString(R.string.poi)).setContent(new Intent(this, SearchPoiFilterActivity.class))); //$NON-NLS-1$ - host.addTab(host.newTabSpec("Search_Address").setIndicator(getString(R.string.address)).setContent(new Intent(this, SearchAddressActivity.class))); //$NON-NLS-1$ + addressSpec = host.newTabSpec("Search_Address").setIndicator(getString(R.string.address)).setContent(new Intent(this, SearchAddressActivity.class));//$NON-NLS-1$ + host.addTab(addressSpec); host.addTab(host.newTabSpec("Search_Location").setIndicator(getString(R.string.search_tabs_location)).setContent(new Intent(this, NavigatePointActivity.class))); //$NON-NLS-1$ + host.addTab(host.newTabSpec("Search_History").setIndicator(getString(R.string.history)).setContent(new Intent(this, SearchHistoryActivity.class))); //$NON-NLS-1$ + } + + public void startSearchAddressOffline(){ + getTabHost().setCurrentTab(0); + addressSpec.setContent(new Intent(this, SearchAddressActivity.class)); + getTabHost().setCurrentTab(1); + } + + public void startSearchAddressOnline(){ + getTabHost().setCurrentTab(0); + addressSpec.setContent(new Intent(this, SearchAddressOnlineActivity.class)); + getTabHost().setCurrentTab(1); } } diff --git a/OsmAnd/src/com/osmand/activities/search/SearchAddressActivity.java b/OsmAnd/src/com/osmand/activities/search/SearchAddressActivity.java index 865faefbc9..ee6de35fbb 100644 --- a/OsmAnd/src/com/osmand/activities/search/SearchAddressActivity.java +++ b/OsmAnd/src/com/osmand/activities/search/SearchAddressActivity.java @@ -1,6 +1,8 @@ package com.osmand.activities.search; +import java.text.MessageFormat; + import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; @@ -42,6 +44,7 @@ public class SearchAddressActivity extends Activity { private Building building = null; private Street street2 = null; private boolean radioBuilding = true; + private Button searchOnline; @Override @@ -56,10 +59,21 @@ public class SearchAddressActivity extends Activity { cityButton = (Button) findViewById(R.id.CityButton); countryButton = (Button) findViewById(R.id.CountryButton); buildingButton = (Button) findViewById(R.id.BuildingButton); + searchOnline = (Button) findViewById(R.id.SearchOnline); attachListeners(); } private void attachListeners() { + if (getParent() instanceof SearchActivity) { + searchOnline.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ((SearchActivity) getParent()).startSearchAddressOnline(); + } + }); + } else { + searchOnline.setVisibility(View.INVISIBLE); + } countryButton.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v) { @@ -159,7 +173,9 @@ public class SearchAddressActivity extends Activity { public void showOnMap(boolean navigateTo){ LatLon l = null; + String historyName = null; int zoom = 12; + boolean en = OsmandSettings.usingEnglishNames(this); if (street2 != null && street != null) { region.preloadWayNodes(street2); region.preloadWayNodes(street); @@ -178,23 +194,28 @@ public class SearchAddressActivity extends Activity { } if(inters != null){ l = inters.getLatLon(); + historyName = MessageFormat.format(getString(R.string.search_history_int_streets), + street.getName(en), street2.getName(en), city.getName(en)); zoom = 16; } } else if (building != null) { l = building.getLocation(); + historyName = MessageFormat.format(getString(R.string.search_history_building), building.getName(en), street.getName(en), city.getName(en)); zoom = 16; } else if (street != null) { l = street.getLocation(); + historyName = MessageFormat.format(getString(R.string.search_history_street), street.getName(en), city.getName(en)); zoom = 14; } else if (city != null) { l = city.getLocation(); + historyName = MessageFormat.format(getString(R.string.search_history_city), city.getName(en)); zoom = 12; } if (l != null) { if(navigateTo){ OsmandSettings.setPointToNavigate(SearchAddressActivity.this, l.getLatitude(), l.getLongitude()); } - OsmandSettings.setMapLocationToShow(SearchAddressActivity.this, l.getLatitude(), l.getLongitude()); + OsmandSettings.setMapLocationToShow(SearchAddressActivity.this, l.getLatitude(), l.getLongitude(), historyName); OsmandSettings.setLastKnownMapZoom(SearchAddressActivity.this, zoom); startActivity(new Intent(SearchAddressActivity.this, MapActivity.class)); diff --git a/OsmAnd/src/com/osmand/activities/search/SearchAddressOnlineActivity.java b/OsmAnd/src/com/osmand/activities/search/SearchAddressOnlineActivity.java new file mode 100644 index 0000000000..6ff29c3ec2 --- /dev/null +++ b/OsmAnd/src/com/osmand/activities/search/SearchAddressOnlineActivity.java @@ -0,0 +1,184 @@ +package com.osmand.activities.search; + +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import org.apache.commons.logging.Log; +import org.xmlpull.v1.XmlPullParser; + +import android.app.ListActivity; +import android.app.ProgressDialog; +import android.content.Intent; +import android.os.Bundle; +import android.util.Xml; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; + +import com.osmand.Algoritms; +import com.osmand.LogUtil; +import com.osmand.OsmandSettings; +import com.osmand.R; +import com.osmand.Version; +import com.osmand.activities.MapActivity; +import com.osmand.osm.LatLon; +import com.osmand.osm.MapUtils; + +public class SearchAddressOnlineActivity extends ListActivity { + + private LatLon location; + private final static Log log = LogUtil.getLog(SearchAddressOnlineActivity.class); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.search_address_online); + Button searchOffline = (Button) findViewById(R.id.SearchOffline); + if (getParent() instanceof SearchActivity) { + searchOffline.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ((SearchActivity) getParent()).startSearchAddressOffline(); + } + }); + } else { + searchOffline.setVisibility(View.INVISIBLE); + } + + Button searchButton = (Button) findViewById(R.id.SearchButton); + searchButton.setOnClickListener(new View.OnClickListener(){ + @Override + public void onClick(View v) { + searchPlaces(((EditText) findViewById(R.id.SearchText)).getText().toString()); + } + }); + location = OsmandSettings.getLastKnownMapLocation(this); + } + + protected void searchPlaces(final String search) { + if(Algoritms.isEmpty(search)){ + return; + } + + final ProgressDialog dlg = ProgressDialog.show(this, getString(R.string.searching), getString(R.string.searching_address)); + new Thread(new Runnable(){ + @Override + public void run() { + try { + final List places = new ArrayList(); + StringBuilder b = new StringBuilder(); + b.append("http://nominatim.openstreetmap.org/search/"); //$NON-NLS-1$ + b.append(URLEncoder.encode(search)); + b.append("?format=xml&addressdetails=0&accept-language=").append(Locale.getDefault().getLanguage()); //$NON-NLS-1$ + log.info("Searching address at : " + b.toString()); //$NON-NLS-1$ + URL url = new URL(b.toString()); + URLConnection conn = url.openConnection(); + conn.setDoInput(true); + conn.setRequestProperty("User-Agent", Version.APP_NAME_VERSION); //$NON-NLS-1$ + conn.connect(); + InputStream is = conn.getInputStream(); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(is, "UTF-8"); //$NON-NLS-1$ + int ev; + while ((ev = parser.next()) != XmlPullParser.END_DOCUMENT) { + if(ev == XmlPullParser.START_TAG){ + if(parser.getName().equals("place")){ //$NON-NLS-1$ + String lat = parser.getAttributeValue("", "lat"); //$NON-NLS-1$ //$NON-NLS-2$ + String lon = parser.getAttributeValue("", "lon"); //$NON-NLS-1$//$NON-NLS-2$ + String displayName = parser.getAttributeValue("", "display_name"); //$NON-NLS-1$ //$NON-NLS-2$ + if(lat != null && lon != null && displayName != null){ + Place p = new Place(); + p.lat = Double.parseDouble(lat); + p.lon = Double.parseDouble(lon); + p.displayName = displayName; + places.add(p); + } + } + } + + } + is.close(); + if(places.isEmpty()){ + showResult(R.string.search_nothing_found, null); + } else { + showResult(0, places); + } + } catch(Exception e){ + log.error("Error searching address", e); //$NON-NLS-1$ + showResult(R.string.error_io_error, null); + } finally { + dlg.dismiss(); + } + } + + }, "SearchingAddress").start(); //$NON-NLS-1$ + + } + + private void showResult(final int warning, final List places) { + runOnUiThread(new Runnable() { + @Override + public void run() { + if(places == null){ + Toast.makeText(SearchAddressOnlineActivity.this, getString(warning), Toast.LENGTH_LONG).show(); + } else { + setListAdapter(new PlacesAdapter(places)); + } + } + }); + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + super.onListItemClick(l, v, position, id); + Place item = ((PlacesAdapter) getListAdapter()).getItem(position); + OsmandSettings.setMapLocationToShow(this, item.lat, item.lon, getString(R.string.address)+ " : " + item.displayName); //$NON-NLS-1$ + startActivity(new Intent(this, MapActivity.class)); + } + + private static class Place { + public double lat; + public double lon; + public String displayName; + } + + class PlacesAdapter extends ArrayAdapter { + + public PlacesAdapter(List places) { + super(SearchAddressOnlineActivity.this, R.layout.search_address_online_list_item, places); + } + + public View getView(int position, View convertView, ViewGroup parent) { + View row = convertView; + if (row == null) { + LayoutInflater inflater = getLayoutInflater(); + row = inflater.inflate(R.layout.search_address_online_list_item, parent, false); + } + Place model = getItem(position); + TextView label = (TextView) row.findViewById(R.id.label); + TextView distanceLabel = (TextView) row.findViewById(R.id.distance_label); + if(location != null){ + int dist = (int) (MapUtils.getDistance(location, model.lat, model.lon)); + distanceLabel.setText(MapUtils.getFormattedDistance(dist)); + } else { + distanceLabel.setText(""); //$NON-NLS-1$ + } + label.setText(model.displayName); + return row; + } + + } + + +} diff --git a/OsmAnd/src/com/osmand/activities/search/SearchHistoryActivity.java b/OsmAnd/src/com/osmand/activities/search/SearchHistoryActivity.java new file mode 100644 index 0000000000..475ed91c3d --- /dev/null +++ b/OsmAnd/src/com/osmand/activities/search/SearchHistoryActivity.java @@ -0,0 +1,119 @@ +package com.osmand.activities.search; + +import java.util.List; + +import android.app.ListActivity; +import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.ImageButton; +import android.widget.ListView; +import android.widget.TextView; + +import com.osmand.OsmandSettings; +import com.osmand.R; +import com.osmand.activities.MapActivity; +import com.osmand.activities.search.SearchHistoryHelper.HistoryEntry; +import com.osmand.osm.LatLon; +import com.osmand.osm.MapUtils; + +public class SearchHistoryActivity extends ListActivity { + private LatLon location; + private SearchHistoryHelper helper; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ListView lv = new ListView(this); + lv.setId(android.R.id.list); + + setContentView(lv); + location = OsmandSettings.getLastKnownMapLocation(this); + helper = SearchHistoryHelper.getInstance(); + + + + } + @Override + protected void onResume() { + super.onResume(); + List historyEntries = helper.getHistoryEntries(this); + + if (!historyEntries.isEmpty()) { + Button clearButton = new Button(this); + clearButton.setText(R.string.clear_all); + clearButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + helper.removeAll(SearchHistoryActivity.this); + setListAdapter(new HistoryAdapter(helper.getHistoryEntries(SearchHistoryActivity.this))); + } + }); + getListView().addFooterView(clearButton); + } + setListAdapter(new HistoryAdapter(historyEntries)); + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + HistoryEntry model = ((HistoryAdapter)getListAdapter()).getItem(position); + selectModel(model); + } + + private void selectModel(HistoryEntry model) { + helper.selectEntry(model, this); + OsmandSettings.setMapLocationToShow(this, model.getLat(), model.getLon()); + startActivity(new Intent(this, MapActivity.class)); + } + + + class HistoryAdapter extends ArrayAdapter { + + public HistoryAdapter(List list) { + super(SearchHistoryActivity.this, R.layout.search_history_list_item, list); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View row = convertView; + if (row == null) { + LayoutInflater inflater = getLayoutInflater(); + row = inflater.inflate(R.layout.search_history_list_item, parent, false); + } + TextView label = (TextView) row.findViewById(R.id.label); + TextView distanceLabel = (TextView) row.findViewById(R.id.distance_label); + ImageButton icon = (ImageButton) row.findViewById(R.id.remove); + final HistoryEntry model = getItem(position); + if(location != null){ + int dist = (int) (MapUtils.getDistance(location, model.lat, model.lon)); + distanceLabel.setText(MapUtils.getFormattedDistance(dist)); + } else { + distanceLabel.setText(""); //$NON-NLS-1$ + } + label.setText(model.name); + icon.setOnClickListener(new View.OnClickListener(){ + @Override + public void onClick(View v) { + helper.remove(model, SearchHistoryActivity.this); + setListAdapter(new HistoryAdapter(helper.getHistoryEntries(SearchHistoryActivity.this))); + } + + }); + View.OnClickListener clickListener = new View.OnClickListener(){ + @Override + public void onClick(View v) { + selectModel(model); + } + + }; + distanceLabel.setOnClickListener(clickListener); + label.setOnClickListener(clickListener); + return row; + } + } + +} diff --git a/OsmAnd/src/com/osmand/activities/search/SearchHistoryHelper.java b/OsmAnd/src/com/osmand/activities/search/SearchHistoryHelper.java new file mode 100644 index 0000000000..5e1584b770 --- /dev/null +++ b/OsmAnd/src/com/osmand/activities/search/SearchHistoryHelper.java @@ -0,0 +1,208 @@ +package com.osmand.activities.search; + +import java.util.ArrayList; +import java.util.List; + +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +public class SearchHistoryHelper { + + private static SearchHistoryHelper helper = new SearchHistoryHelper(); + private static final int HISTORY_LIMIT = 10; + + public static SearchHistoryHelper getInstance(){ + return helper; + } + + public static class HistoryEntry { + double lat; + double lon; + String name; + + public HistoryEntry(double lat, double lon, String name){ + this.lat = lat; + this.lon = lon; + this.name = name; + + } + + public String getName() { + return name; + } + + public double getLat() { + return lat; + } + public double getLon() { + return lon; + } + } + + private List loadedEntries = null; + + + public List getHistoryEntries(Context ctx) { + if(loadedEntries == null){ + HistoryItemDBHelper helper = checkLoadedEntries(ctx); + helper.close(); + } + return loadedEntries; + } + + private HistoryItemDBHelper checkLoadedEntries(Context ctx){ + HistoryItemDBHelper helper = new HistoryItemDBHelper(ctx); + if(loadedEntries == null){ + loadedEntries = helper.getEntries(); + } + return helper; + } + + public void remove(HistoryEntry model, Context ctx) { + HistoryItemDBHelper helper = checkLoadedEntries(ctx); + if(helper.remove(model)){ + loadedEntries.remove(model); + } + helper.close(); + } + + public void removeAll(Context ctx) { + HistoryItemDBHelper helper = checkLoadedEntries(ctx); + if(helper.removeAll()){ + loadedEntries.clear(); + } + helper.close(); + } + + public void selectEntry(HistoryEntry model, Context ctx) { + HistoryItemDBHelper helper = checkLoadedEntries(ctx); + int i = loadedEntries.indexOf(model); + updateModelAt(model, helper, i); + helper.close(); + } + + private void updateModelAt(HistoryEntry model, HistoryItemDBHelper helper, int i) { + if(i == -1){ + if(helper.add(model)){ + loadedEntries.add(0, model); + if(loadedEntries.size() > HISTORY_LIMIT){ + if(helper.remove(loadedEntries.get(loadedEntries.size() - 1))){ + loadedEntries.remove(loadedEntries.size() - 1); + } + } + } + } else { + if(helper.update(model)){ + loadedEntries.remove(i); + loadedEntries.add(0, model); + } + } + } + + public HistoryEntry addNewItemToHistory(double lat, double lon, String description, Context ctx){ + HistoryItemDBHelper helper = checkLoadedEntries(ctx); + int i = 0; + HistoryEntry model = new HistoryEntry(lat, lon, description); + for(HistoryEntry e : loadedEntries){ + if(description.equals(e.getName())){ + break; + } + i++; + } + if(i == loadedEntries.size()){ + i = -1; + } + updateModelAt(model, helper, i); + helper.close(); + return model; + } + + private static class HistoryItemDBHelper extends SQLiteOpenHelper { + + private static final String DB_NAME = "search_history"; //$NON-NLS-1$ + private static final int DB_VERSION = 1; + private static final String HISTORY_TABLE_NAME = "history"; //$NON-NLS-1$ + private static final String HISTORY_COL_NAME = "name"; //$NON-NLS-1$ + private static final String HISTORY_COL_TIME = "time"; //$NON-NLS-1$ + private static final String HISTORY_COL_TYPE = "type"; //$NON-NLS-1$ + private static final String HISTORY_COL_LAT = "latitude"; //$NON-NLS-1$ + private static final String HISTORY_COL_LON = "longitude"; //$NON-NLS-1$ + private static final String HISTORY_TABLE_CREATE = "CREATE TABLE " + HISTORY_TABLE_NAME + " (" + //$NON-NLS-1$ //$NON-NLS-2$ + HISTORY_COL_NAME + " TEXT, " + HISTORY_COL_TIME + " long, " + HISTORY_COL_TYPE + " TEXT, " + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + HISTORY_COL_LAT + " double, " +HISTORY_COL_LON + " double);"; //$NON-NLS-1$ //$NON-NLS-2$ + + + public HistoryItemDBHelper(Context context) { + super(context, DB_NAME, null, DB_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL(HISTORY_TABLE_CREATE); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + } + + public boolean remove(HistoryEntry e){ + SQLiteDatabase db = getWritableDatabase(); + if(db != null){ + db.execSQL("DELETE FROM "+ HISTORY_TABLE_NAME+ " WHERE " + HISTORY_COL_NAME+ " = ?", new Object[]{e.getName()}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + return true; + } + return false; + } + + public boolean removeAll(){ + SQLiteDatabase db = getWritableDatabase(); + if(db != null){ + db.execSQL("DELETE FROM "+ HISTORY_TABLE_NAME); //$NON-NLS-1$ + return true; + } + return false; + } + + public boolean update(HistoryEntry e){ + SQLiteDatabase db = getWritableDatabase(); + if(db != null){ + db.execSQL("UPDATE "+ HISTORY_TABLE_NAME+ " SET time = ? WHERE " + HISTORY_COL_NAME+ " = ?", new Object[]{System.currentTimeMillis(), e.getName()}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + return true; + } + return false; + } + + public boolean add(HistoryEntry e){ + SQLiteDatabase db = getWritableDatabase(); + if(db != null){ + db.execSQL("INSERT INTO "+ HISTORY_TABLE_NAME+ " VALUES (?, ?, ?, ?, ?)", new Object[]{e.getName(), System.currentTimeMillis(), null, e.getLat(), e.getLon()}); //$NON-NLS-1$ //$NON-NLS-2$ + return true; + } + return false; + } + + public List getEntries(){ + List entries = new ArrayList(); + SQLiteDatabase db = getReadableDatabase(); + if(db != null){ + Cursor query = db.rawQuery("SELECT " + HISTORY_COL_NAME +", " + HISTORY_COL_LAT +"," + HISTORY_COL_LON +" FROM " + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + HISTORY_TABLE_NAME + " ORDER BY " + HISTORY_COL_TIME + " DESC", null); //$NON-NLS-1$//$NON-NLS-2$ + if(query.moveToFirst()){ + do { + HistoryEntry e = new HistoryEntry(query.getDouble(1), query.getDouble(2), query.getString(0)); + entries.add(e); + } while(query.moveToNext()); + } + query.close(); + } + return entries; + } + + } + + + + +} diff --git a/OsmAnd/src/com/osmand/activities/search/SearchPOIActivity.java b/OsmAnd/src/com/osmand/activities/search/SearchPOIActivity.java index ec6a02b9ca..adae759fd4 100644 --- a/OsmAnd/src/com/osmand/activities/search/SearchPOIActivity.java +++ b/OsmAnd/src/com/osmand/activities/search/SearchPOIActivity.java @@ -118,7 +118,7 @@ public class SearchPOIActivity extends ListActivity { public void onListItemClick(ListView parent, View v, int position, long id) { Amenity amenity = ((AmenityAdapter) getListAdapter()).getItem(position); - OsmandSettings.setMapLocationToShow(this, amenity.getLocation().getLatitude(), amenity.getLocation().getLongitude()); + OsmandSettings.setMapLocationToShow(this, amenity.getLocation().getLatitude(), amenity.getLocation().getLongitude(), getString(R.string.poi)+" : " + amenity.getSimpleFormat(OsmandSettings.usingEnglishNames(this))); //$NON-NLS-1$ Intent newIntent = new Intent(SearchPOIActivity.this, MapActivity.class); startActivity(newIntent); }