diff --git a/DataExtractionOSM/src/com/osmand/ToDoConstants.java b/DataExtractionOSM/src/com/osmand/ToDoConstants.java
index 9489dcc5e3..8a9793b224 100644
--- a/DataExtractionOSM/src/com/osmand/ToDoConstants.java
+++ b/DataExtractionOSM/src/com/osmand/ToDoConstants.java
@@ -34,6 +34,10 @@ public class ToDoConstants {
// 8. Introduce activity search by location (unify with existing dialog)
// 9. When all features will be ready we can remove show location from context menu
+ // Performance improvements Android :
+ // 1. Introducing one place where refreshMap will be called using postMessage mechanism (delay more than > 50 ? ms)
+ // 2. Introducing cache of file names that are on disk (creating new File() consumes a lot of memory)
+
// TODO SWING:
// 2. Configure file log & see log from file (add uncaught exception handling)
// 5. Implement suppress warning for duplicate id
diff --git a/DataExtractionOSM/src/com/osmand/data/City.java b/DataExtractionOSM/src/com/osmand/data/City.java
index 63156b06db..fe0fa44c4f 100644
--- a/DataExtractionOSM/src/com/osmand/data/City.java
+++ b/DataExtractionOSM/src/com/osmand/data/City.java
@@ -55,6 +55,9 @@ public class City extends MapObject {
this.type = type;
}
+ public boolean isEmptyWithStreets(){
+ return streets.isEmpty();
+ }
public Street registerStreet(String street){
if(!streets.containsKey(street.toLowerCase())){
diff --git a/OsmAnd/AndroidManifest.xml b/OsmAnd/AndroidManifest.xml
index 2afc0d9c41..4a5e267f2b 100644
--- a/OsmAnd/AndroidManifest.xml
+++ b/OsmAnd/AndroidManifest.xml
@@ -18,7 +18,7 @@
-
+
diff --git a/OsmAnd/res/layout/search_address.xml b/OsmAnd/res/layout/search_address.xml
new file mode 100644
index 0000000000..075b15d863
--- /dev/null
+++ b/OsmAnd/res/layout/search_address.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OsmAnd/res/layout/search_by_name.xml b/OsmAnd/res/layout/search_by_name.xml
new file mode 100644
index 0000000000..ebea9b3654
--- /dev/null
+++ b/OsmAnd/res/layout/search_by_name.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/OsmAnd/res/layout/searchaddress.xml b/OsmAnd/res/layout/searchaddress.xml
deleted file mode 100644
index fe20d9d7ce..0000000000
--- a/OsmAnd/res/layout/searchaddress.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
diff --git a/OsmAnd/res/layout/searchbyname_list.xml b/OsmAnd/res/layout/searchbyname_list.xml
new file mode 100644
index 0000000000..2e53e2a7ab
--- /dev/null
+++ b/OsmAnd/res/layout/searchbyname_list.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/OsmAnd/res/layout/searchpoi.xml b/OsmAnd/res/layout/searchpoi.xml
index f4238a877e..7257d5be25 100644
--- a/OsmAnd/res/layout/searchpoi.xml
+++ b/OsmAnd/res/layout/searchpoi.xml
@@ -2,10 +2,10 @@
-
+ android:layout_height="fill_parent">
+
+
\ No newline at end of file
diff --git a/OsmAnd/res/layout/searchpoilist.xml b/OsmAnd/res/layout/searchpoilist.xml
index 15ba603a6f..6e09207594 100644
--- a/OsmAnd/res/layout/searchpoilist.xml
+++ b/OsmAnd/res/layout/searchpoilist.xml
@@ -2,10 +2,9 @@
+ android:layout_height="fill_parent">
+ android:layout_height="fill_parent" >
\ No newline at end of file
diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml
index 6efb660846..13975015b7 100644
--- a/OsmAnd/res/values/strings.xml
+++ b/OsmAnd/res/values/strings.xml
@@ -1,5 +1,10 @@
+ Search address
+ Choose building
+ Choose street
+ Choose city
+ Choose country
Choose postion on the map
Position on the map
Specify point
diff --git a/OsmAnd/src/com/osmand/AmenityIndexRepository.java b/OsmAnd/src/com/osmand/AmenityIndexRepository.java
index b33462b3cd..4dc6d62d6b 100644
--- a/OsmAnd/src/com/osmand/AmenityIndexRepository.java
+++ b/OsmAnd/src/com/osmand/AmenityIndexRepository.java
@@ -133,15 +133,19 @@ public class AmenityIndexRepository {
dataBottomLatitude = query.getDouble(2);
dataLeftLongitude = query.getDouble(3);
}
+ query.close();
if (log.isDebugEnabled()) {
log.debug("Initializing db " + file.getAbsolutePath() + " " + (System.currentTimeMillis() - start) + "ms");
}
}
- public void close(){
+ public synchronized void close(){
if(db != null){
db.close();
+ dataRightLongitude = dataLeftLongitude = dataBottomLatitude= dataTopLatitude = 0;
+ cachedAmenities.clear();
+ cTopLatitude = cBottomLatitude = cLeftLongitude = cRightLongitude = 0;
}
}
diff --git a/OsmAnd/src/com/osmand/OsmandSettings.java b/OsmAnd/src/com/osmand/OsmandSettings.java
index dcf833290b..95a5899fec 100644
--- a/OsmAnd/src/com/osmand/OsmandSettings.java
+++ b/OsmAnd/src/com/osmand/OsmandSettings.java
@@ -117,5 +117,40 @@ public class OsmandSettings {
edit.putInt(LAST_KNOWN_MAP_ZOOM, zoom);
edit.commit();
}
+
+ public static final String LAST_SEARCHED_REGION = "last_searched_region";
+ public static final String LAST_SEARCHED_CITY = "last_searched_city";
+ public static final String LAST_SEARCHED_STREET = "last_searched_street";
+
+ public static String getLastSearchedRegion(Context ctx){
+ SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE);
+ return prefs.getString(LAST_SEARCHED_REGION, "");
+ }
+
+ public static boolean setLastSearchedRegion(Context ctx, String region){
+ SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE);
+ return prefs.edit().putString(LAST_SEARCHED_REGION, region).commit();
+ }
+ public static Long getLastSearchedCity(Context ctx){
+ SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE);
+ return prefs.getLong(LAST_SEARCHED_CITY, -1);
+ }
+
+ public static boolean setLastSearchedCity(Context ctx, Long cityId){
+ SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE);
+ return prefs.edit().putLong(LAST_SEARCHED_CITY, cityId).commit();
+ }
+
+ public static String getLastSearchedStreet(Context ctx){
+ SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE);
+ return prefs.getString(LAST_SEARCHED_STREET, "");
+ }
+
+ public static boolean setLastSearchedStreet(Context ctx, String street){
+ SharedPreferences prefs = ctx.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_WORLD_READABLE);
+ return prefs.edit().putString(LAST_SEARCHED_STREET, street).commit();
+ }
+
+
}
diff --git a/OsmAnd/src/com/osmand/RegionAddressRepository.java b/OsmAnd/src/com/osmand/RegionAddressRepository.java
new file mode 100644
index 0000000000..ec5627f79d
--- /dev/null
+++ b/OsmAnd/src/com/osmand/RegionAddressRepository.java
@@ -0,0 +1,166 @@
+package com.osmand;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.TreeMap;
+
+import org.apache.commons.logging.Log;
+
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+
+import com.osmand.data.Building;
+import com.osmand.data.City;
+import com.osmand.data.Street;
+import com.osmand.data.City.CityType;
+import com.osmand.data.index.IndexConstants;
+import com.osmand.data.index.IndexConstants.IndexCityTable;
+import com.osmand.data.index.IndexConstants.IndexStreetTable;
+
+
+public class RegionAddressRepository {
+ private static final Log log = LogUtil.getLog(RegionAddressRepository.class);
+ private SQLiteDatabase db;
+ private String name;
+ private LinkedHashMap cities = new LinkedHashMap();
+ private TreeMap> cityTypes = new TreeMap>();
+
+ public void initialize(final IProgress progress, File file) {
+ long start = System.currentTimeMillis();
+ if(db != null){
+ // close previous db
+ db.close();
+ }
+ db = SQLiteDatabase.openOrCreateDatabase(file, null);
+ name = file.getName().substring(0, file.getName().indexOf('.'));
+ if (log.isDebugEnabled()) {
+ log.debug("Initializing address db " + file.getAbsolutePath() + " " + (System.currentTimeMillis() - start) + "ms");
+ }
+ }
+
+ public void close(){
+ if(db != null){
+ db.close();
+ }
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void clearCities(){
+ cities.clear();
+ cityTypes.clear();
+ }
+
+ public City getCityById(Long id){
+ preloadCities();
+ return cities.get(id);
+ }
+
+ public Street getStreetByName(City city, String name){
+ if(city.isEmptyWithStreets()){
+ preloadStreets(city);
+ }
+ return city.getStreet(name);
+ }
+
+ public Building getBuildingByName(Street street, String name){
+ if(street.getBuildings().isEmpty()){
+ preloadBuildings(street);
+ }
+ for(Building b : street.getBuildings()){
+ if(b.getName().equals(name)){
+ return b;
+ }
+ }
+ return null;
+ }
+
+ public void fillWithSuggestedCities(String name, List citiesToFill, List source){
+ preloadCities();
+ if(name.length() < 3){
+ EnumSet set = EnumSet.of(CityType.CITY, CityType.TOWN);
+ for(CityType t : set){
+ if(name.length() == 0){
+ citiesToFill.addAll(cityTypes.get(t));
+ } else {
+ name = name.toLowerCase();
+ for (City c : cityTypes.get(t)) {
+ String lowerCase = c.getName().toLowerCase();
+ if(lowerCase.startsWith(name)){
+ citiesToFill.add(c);
+ }
+ }
+ }
+ }
+ } else {
+ // essentially index is created that cities towns are first in cities map
+ name = name.toLowerCase();
+ int ind = 0;
+ Collection src = source == null ? cities.values() : source;
+ for (City c : src) {
+ String lowerCase = c.getName().toLowerCase();
+ if (lowerCase.startsWith(name)) {
+ citiesToFill.add(ind, c);
+ ind++;
+ } else if (lowerCase.contains(name)) {
+ citiesToFill.add(c);
+ }
+ }
+ }
+ }
+
+ public void preloadBuildings(Street str){
+ // TODO
+ }
+
+ public void preloadStreets(City city){
+ if (city.isEmptyWithStreets()) {
+ Cursor query = db.query(IndexStreetTable.getTable(), IndexConstants.generateColumnNames(IndexStreetTable.values()), "? = city",
+ new String[] { city.getId() + "" }, null, null, null);
+ if (query.moveToFirst()) {
+ do {
+ Street street = new Street(city);
+ street.setId(query.getLong(IndexStreetTable.ID.ordinal()));
+ street.setLocation(query.getDouble(IndexStreetTable.LATITUDE.ordinal()), query.getDouble(IndexStreetTable.LONGITUDE
+ .ordinal()));
+ street.setName(query.getString(IndexStreetTable.NAME.ordinal()));
+ city.registerStreet(street);
+ } while (query.moveToNext());
+ }
+ query.close();
+ }
+ }
+
+ public void preloadCities(){
+ if (cities.isEmpty()) {
+ Cursor query = db.query(IndexCityTable.getTable(), IndexConstants.generateColumnNames(IndexCityTable.values()), null, null,
+ null, null, null);
+ if(query.moveToFirst()){
+ do {
+ CityType type = CityType.valueFromString(query.getString(IndexCityTable.CITY_TYPE.ordinal()));
+ if (type != null) {
+ City city = new City(type);
+ city.setId(query.getLong(IndexCityTable.ID.ordinal()));
+ city.setLocation(query.getDouble(IndexCityTable.LATITUDE.ordinal()), query.getDouble(IndexCityTable.LONGITUDE
+ .ordinal()));
+ city.setName(query.getString(IndexCityTable.NAME.ordinal()));
+ cities.put(city.getId(), city);
+
+ if(!cityTypes.containsKey(type)){
+ cityTypes.put(type, new ArrayList());
+ }
+ cityTypes.get(type).add(city);
+ }
+
+ } while(query.moveToNext());
+ }
+ query.close();
+ }
+ }
+}
diff --git a/OsmAnd/src/com/osmand/ResourceManager.java b/OsmAnd/src/com/osmand/ResourceManager.java
index c64cf6984f..40c7db2d34 100644
--- a/OsmAnd/src/com/osmand/ResourceManager.java
+++ b/OsmAnd/src/com/osmand/ResourceManager.java
@@ -2,6 +2,7 @@ package com.osmand;
import java.io.File;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -15,7 +16,6 @@ import android.graphics.BitmapFactory;
import android.os.Environment;
import com.osmand.data.Amenity;
-import com.osmand.data.Region;
import com.osmand.data.index.IndexConstants;
import com.osmand.data.preparation.MapTileDownloader;
import com.osmand.data.preparation.MapTileDownloader.DownloadRequest;
@@ -58,11 +58,10 @@ public class ResourceManager {
private MapTileDownloader downloader = MapTileDownloader.getInstance();
// Indexes
- private Map addressMap = new TreeMap();
+ private Map addressMap = new TreeMap();
protected List amenityRepositories = new ArrayList();
-
public AsyncLoadingThread asyncLoadingTiles = new AsyncLoadingThread();
@@ -154,7 +153,7 @@ public class ResourceManager {
// POI INDEX //
public void indexingPoi(final IProgress progress) {
File file = new File(Environment.getExternalStorageDirectory(), POI_PATH);
- clearAmenities();
+ closeAmenities();
if (file.exists() && file.canRead()) {
for (File f : file.listFiles()) {
if (f.getName().endsWith(IndexConstants.POI_INDEX_EXT)) {
@@ -170,7 +169,7 @@ public class ResourceManager {
public void indexingAddresses(final IProgress progress){
File file = new File(Environment.getExternalStorageDirectory(), ADDRESS_PATH);
- clearAddresses();
+ closeAddresses();
if (file.exists() && file.canRead()) {
for (File f : file.listFiles()) {
if (f.getName().endsWith(IndexConstants.ADDRESS_INDEX_EXT)) {
@@ -212,23 +211,35 @@ public class ResourceManager {
}
}
- ////////////////////////////////////////////// Working with amenities ////////////////////////////////////////////////
+ ////////////////////////////////////////////// Working with address ///////////////////////////////////////////
- public void clearAmenities(){
+ public RegionAddressRepository getRegionRepository(String name){
+ return addressMap.get(name);
+ }
+
+ public Collection getAddressRepositories(){
+ return addressMap.values();
+ }
+
+ ////////////////////////////////////////////// Closing methods ////////////////////////////////////////////////
+
+ public void closeAmenities(){
for(AmenityIndexRepository r : amenityRepositories){
r.close();
}
amenityRepositories.clear();
}
- public void clearAddresses(){
- // TODO close db connections
+ public void closeAddresses(){
+ for(RegionAddressRepository r : addressMap.values()){
+ r.close();
+ }
addressMap.clear();
}
public synchronized void close(){
- clearAmenities();
- clearAddresses();
+ closeAmenities();
+ closeAddresses();
}
/// On low memory method ///
diff --git a/OsmAnd/src/com/osmand/activities/search/SearchActivity.java b/OsmAnd/src/com/osmand/activities/search/SearchActivity.java
index 9c43b07708..1d886716e9 100644
--- a/OsmAnd/src/com/osmand/activities/search/SearchActivity.java
+++ b/OsmAnd/src/com/osmand/activities/search/SearchActivity.java
@@ -35,7 +35,7 @@ public class SearchActivity extends TabActivity {
// });
TabHost host = getTabHost();
host.addTab(host.newTabSpec("Search_POI").setIndicator("Search POI").setContent(new Intent(this, SearchPOIListActivity.class)));
- host.addTab(host.newTabSpec("Search_Adress").setIndicator("Search Address").setContent(new Intent(this, SearchAddress.class)));
+ host.addTab(host.newTabSpec("Search_Adress").setIndicator("Search Address").setContent(new Intent(this, SearchAddressActivity.class)));
}
}
diff --git a/OsmAnd/src/com/osmand/activities/search/SearchAddress.java b/OsmAnd/src/com/osmand/activities/search/SearchAddress.java
deleted file mode 100644
index e666526366..0000000000
--- a/OsmAnd/src/com/osmand/activities/search/SearchAddress.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.osmand.activities.search;
-
-
-import com.osmand.R;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class SearchAddress extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.searchaddress);
- }
-}
diff --git a/OsmAnd/src/com/osmand/activities/search/SearchAddressActivity.java b/OsmAnd/src/com/osmand/activities/search/SearchAddressActivity.java
new file mode 100644
index 0000000000..e50ebcbb78
--- /dev/null
+++ b/OsmAnd/src/com/osmand/activities/search/SearchAddressActivity.java
@@ -0,0 +1,131 @@
+package com.osmand.activities.search;
+
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+
+import com.osmand.OsmandSettings;
+import com.osmand.R;
+import com.osmand.RegionAddressRepository;
+import com.osmand.ResourceManager;
+import com.osmand.data.Building;
+import com.osmand.data.City;
+import com.osmand.data.Street;
+
+public class SearchAddressActivity extends Activity {
+
+ private Button showOnMap;
+ private Button streetButton;
+ private Button cityButton;
+ private Button countryButton;
+ private Button buildingButton;
+
+ private RegionAddressRepository region = null;
+ private City city = null;
+ private Street street = null;
+ private Building building = null;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ setContentView(R.layout.search_address);
+
+ showOnMap = (Button) findViewById(R.id.ShowOnMap);
+ streetButton = (Button) findViewById(R.id.StreetButton);
+ cityButton = (Button) findViewById(R.id.CityButton);
+ countryButton = (Button) findViewById(R.id.CountryButton);
+ buildingButton = (Button) findViewById(R.id.BuildingButton);
+ findViewById(R.id.ResetBuilding).setOnClickListener(new View.OnClickListener(){
+ @Override
+ public void onClick(View v) {
+ building = null;
+ updateUI();
+ }
+ });
+ findViewById(R.id.ResetStreet).setOnClickListener(new View.OnClickListener(){
+ @Override
+ public void onClick(View v) {
+ street = null;
+ building = null;
+ updateUI();
+ }
+ });
+ findViewById(R.id.ResetCity).setOnClickListener(new View.OnClickListener(){
+ @Override
+ public void onClick(View v) {
+ city = null;
+ street = null;
+ building = null;
+ updateUI();
+ }
+ });
+ findViewById(R.id.ResetCountry).setOnClickListener(new View.OnClickListener(){
+ @Override
+ public void onClick(View v) {
+ region = null;
+ city = null;
+ street = null;
+ building = null;
+ updateUI();
+ }
+ });
+ }
+
+ protected void updateUI(){
+ findViewById(R.id.ResetCountry).setEnabled(region != null);
+ if(region == null){
+ countryButton.setText(R.string.ChooseCountry);
+ } else {
+ countryButton.setText(region.getName());
+ }
+ findViewById(R.id.ResetCity).setEnabled(city != null);
+ if(city == null){
+ cityButton.setText(R.string.choose_city);
+ } else {
+ cityButton.setText(city.getName());
+ }
+ cityButton.setEnabled(region != null);
+
+ findViewById(R.id.ResetStreet).setEnabled(street != null);
+ if(street == null){
+ streetButton.setText(R.string.choose_street);
+ } else {
+ streetButton.setText(street.getName());
+ }
+ streetButton.setEnabled(city != null);
+
+ findViewById(R.id.ResetBuilding).setEnabled(building != null);
+ if(building == null){
+ buildingButton.setText(R.string.choose_building);
+ } else {
+ buildingButton.setText(building.getName());
+ }
+ buildingButton.setEnabled(street != null);
+ showOnMap.setEnabled(building != null || city != null || street != null);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ region = null;
+ city = null;
+ street = null;
+ building = null;
+ String lastSearchedRegion = OsmandSettings.getLastSearchedRegion(this);
+ region = ResourceManager.getResourceManager().getRegionRepository(lastSearchedRegion);
+ if(region != null){
+ city = region.getCityById(OsmandSettings.getLastSearchedCity(this));
+ if(city != null){
+ street = region.getStreetByName(city, OsmandSettings.getLastSearchedStreet(this));
+ }
+ }
+
+ updateUI();
+ }
+
+
+}
diff --git a/OsmAnd/src/com/osmand/activities/search/SearchCityByNameActivity.java b/OsmAnd/src/com/osmand/activities/search/SearchCityByNameActivity.java
new file mode 100644
index 0000000000..f3c9a217c8
--- /dev/null
+++ b/OsmAnd/src/com/osmand/activities/search/SearchCityByNameActivity.java
@@ -0,0 +1,16 @@
+package com.osmand.activities.search;
+
+import com.osmand.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Window;
+
+public class SearchCityByNameActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ setContentView(R.layout.search_by_name);
+ }
+}
diff --git a/OsmAnd/src/com/osmand/activities/search/SearchRegionByNameActivity.java b/OsmAnd/src/com/osmand/activities/search/SearchRegionByNameActivity.java
new file mode 100644
index 0000000000..0e65f83bbc
--- /dev/null
+++ b/OsmAnd/src/com/osmand/activities/search/SearchRegionByNameActivity.java
@@ -0,0 +1,57 @@
+package com.osmand.activities.search;
+
+import java.util.Collection;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Window;
+
+import com.osmand.R;
+import com.osmand.RegionAddressRepository;
+import com.osmand.ResourceManager;
+
+public class SearchRegionByNameActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ setContentView(R.layout.search_by_name);
+ Collection repos = ResourceManager.getResourceManager().getAddressRepositories();
+// setListAdapter(new ArrayAdapter);
+ }
+
+ /*class NamesAdapter extends ArrayAdapter