04 Searching
Overview
Searching Functions
Base
You can use your results from Tutorial03
as a base for our new project.
Project requirements
We will use the Android FloatingActionButton from the android support library in this tutorial. So please add the dependency to your build.gradle
.
... dependencies { ... compile "com.android.support:design:26.1.0" }
Search basics
Important
Every search besides the Point Of Interest (POI) search will only take place in the currently opened map. To search in another map, you have to switch it to the one you would like to search in!
The Navigation-SDK provides multiple possibilities for searching towns, streets in towns, house numbers in streets, point of interests and much more:
Search method | Description | Depends on |
---|---|---|
searchTown() | Search a town by a given name or name fragment | - |
searchStreet() | Search a street in a former town or postcode result by a name or name fragment of the street | town result |
searchHouseNr() | Search a house number in a former found town and street result | town, street result |
searchCrossing() | Search crossings in a former found street result | street result |
searchPOI() | Search POIs with a given name around a position or globally | - |
searchPostcode() | Search a town by postcode | - |
simpleGeoCode() | Search a complete given address and returns it's position | - |
simpleInvGeoCode() | Search an address of a given position | - |
As you can see, some of the searches like the street search need a former result. You can only search a street in a previous found town and you can only search house numbers in a known street of a known town.
Adding a simple town search
Every search is built up by the following steps:
- Fill a search request with what you want to search
- Call the appropriate search function with the request as parameter
- Get a single generic result by calling SearchResult result = results.get(index) with the wanted index
First, let us add a fab button to our MainActivity. For now, we use it to start the search. Later on, we will use it to switch to a search activity. This is explained in one of the next chapters. Add the following xml snippet to the activity_main.xml right after the MapView section:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.ptvag.navigation.tutorial.MainActivity"> <com.ptvag.navigation.tutorial.MapView android:id="@+id/map" android:layout_width="match_parent" android:layout_height="match_parent" /> <android.support.design.widget.FloatingActionButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:layout_margin="16dp" android:src="@android:drawable/ic_dialog_map" android:onClick="onFloatingButtonClicked"/> </RelativeLayout>
As you can see, we connected the button with the method onFloatingButtonClicked, which we implement in our MainActivity. We also realize a simple town search example. Add the following code to your MainActivity:
public void onFloatingButtonClicked(View view) { SearchRequest request = new SearchRequest("karls", null, (short)0, SearchKind.SDK_SK_TOWNBYNAME_SORTED); int resultCount = 0; try { SearchResults results = NavigationSDK.searchTown(request, 100, true); for(SearchResult result: results) { float latitude = (float) result.getPosition().toGeoPosition().getLatitude(); latitude = latitude / SDK_GEOCONVERSION_FACTOR; float longitude = (float) result.getPosition().toGeoPosition().getLongitude(); longitude = longitude / SDK_GEOCONVERSION_FACTOR; Log.e("Results:", result.getName() + ", Latitude: " + latitude + ", Longitude: " + longitude + "\n"); } } catch (NavigationException e) { e.printStackTrace(); } }
Start the program and take a look into the logcat to get the result output. We get a bunch of cities which all have a name beginning with "karls".
Now comes a step by step introduction of the previous code to get a more detailed view:
First, we fill out the SearchRequest "request" with the needed parameters:
SearchRequest request = new SearchRequest("karls", null, (short)0, SearchKind.SDK_SK_TOWNBYNAME_SORTED);
The SearchRequest class has the following members:
- Name: The name (or name fragment of the town we would like to search, "karls" in our example)
- Position: An optional position around the search should take place. If set to "null" we search alphabetically, not in a radius around a position
- Country Code: An optional country code to filter the result (useful for maps that consists of multiple countries). If set to 0, we will get every town that matches
- SearchKind: The kind of search (we want a town search result which orders the towns in a reasonable way (biggest towns first, then districts of towns) so we set it to SearchKind.SDK_SK_TOWNBYNAME_SORTED)
The search itself is called by:
SearchResults results = NavigationSDK.searchTown(request, 100, true);
- The first parameter is the above filled request
- The second parameter declares the maxium number of results that should be returned
- The third parameter means "one entry per town" When set, towns which have the same name but different postcodes will be filtered out.
The return value of the search is a collection of SearchResult(s) object.
To get a single result, we call:
SearchResult result = results.get(index);
This SearchResult object holds all data of a single result:
- SearchKind: The kind of the result, see SearchKind for details
- Name: The name of the result item
- Country Code: The country code of the item
- Category: The category of the result, not ued for house numbers
- Type: The returned kind of the result item (same type as SearchKind)
- Position: the position of the result item
The logcat output is generated by:
Log.e("Results:", "Res("+i+"):" + result.getName() + ", Latitude: " + (float)result.getPosition().toGeoPosition().getLatitude()/SDK_GEOCONVERSION_FACTOR + ", Longitude: " + (float)result.getPosition().toGeoPosition().getLongitude()/SDK_GEOCONVERSION_FACTOR + "\n");
As you can see in the code above, we print out the result name and the geodecimal position of the result.
Because the geodecimal position is hold internally as an integer value, we have to cast the result latitude and longitude values to float and divide it with the constant value NavigationSDK.SDK_GEOCONVERSION_FACTOR.
Important
You have to clear not longer used search results by calling SearchResults.destroy() to avoid memory leaks!
Creating an interactive search
The next thing we do is to implement an interactive address search. For this, we have to add and change some code in our project:
Change the onFloatingButtonClicked()
method in the MainActivity:
To be able to switch to our new activity, we remove the sample search code from the onFloatingButtonClicked()
method and replace it.
So the onFloatingButtonClicked()
Method should look like this:
public void onFloatingButtonClicked(View view) { Intent intent = new Intent(this, SearchActivity.class); startActivity(intent); }
Add the search activity:
We add two new activities to our project. A search overview and a result activity. Right click on the project and add an empty activity called SearchActivity. This SearchActivity will be the starting point for all the searches we implement in this chapter. Do the same again and add a new activity called ResultListActivity. To feed the ResultListActivity with data, we add a SearchAdapter and a SearchModel. The model will execute the current search and the adapter provides the result to the ListView.
SearchModel
The SearchModel provides methods to search towns, streets and house numbers, to get the count of the results and the results itself. The search methods look very similar to the first search we created in the MainActivity. As you can see, the street search needs a former town search result, and the house number search needs a town and a street search result. For convenience reasons, the SearchModel object will be created once at startup in the Application class. This is not mandatory, but for this tutorial, it is the simplest way to access the model from all activities and from the SearchAdapter. Let's add the following to the Application class:
private static SearchModel mModel = new SearchModel(); ... public static SearchModel getSearchModel() { return mModel; }
The SearchModel class should look like this:
public class SearchModel { private static final int MAXTOWNHITS = 500; private static final int MAXSTREETHITS = 500; private static final int MAXHNRHITS = 20; private SearchResults mTownResults = null; private SearchResults mStreetResults = null; private SearchResults mHNRResults = null; public SearchModel() { } public void searchTown(String name, int cc) { resetTownSearch(); SearchRequest request = new SearchRequest(name, null, (short) cc, SearchKind.SDK_SK_TOWNBYNAME_SORTED); try { mTownResults = NavigationSDK.searchTown(request, MAXTOWNHITS, true); } catch (NavigationException e) { e.printStackTrace(); } } public void searchStreet(String name, SearchResult formerTownResult) { resetStreetSearch(); SearchRequest request = new SearchRequest(name, null, (short) 0, SearchKind.SDK_SK_STREETBYNAME); try { mStreetResults = NavigationSDK.searchStreet(request, MAXSTREETHITS, formerTownResult); } catch (NavigationException e) { e.printStackTrace(); } } public void searchHNR(String name, SearchResult formerTownResult, SearchResult formerStreetResult) { resetHNRSearch(); SearchRequest request = new SearchRequest(name, null, (short) 0, SearchKind.SDK_SK_HNR); try { mHNRResults = NavigationSDK.searchHouseNr(request, MAXHNRHITS, formerTownResult, formerStreetResult); } catch (NavigationException e) { e.printStackTrace(); } } public int count(SearchKind type) { if (type == SearchKind.SDK_SK_TOWNBYNAME || type == SearchKind.SDK_SK_TOWNBYNAME_SORTED && mTownResults != null) return mTownResults.size(); else if (type == SearchKind.SDK_SK_STREETBYNAME && mStreetResults != null) return mStreetResults.size(); else if (type == SearchKind.SDK_SK_HNR && mHNRResults != null) return mHNRResults.size(); else return 0; } public SearchResult getResult(int index, SearchKind type) { SearchResult result = new SearchResult(); if (mTownResults != null && (type == SearchKind.SDK_SK_TOWNBYNAME || type == SearchKind.SDK_SK_TOWNBYNAME_SORTED)) { if (index >= 0 && index < mTownResults.size()) result = mTownResults.get(index); } else if (mStreetResults != null && (type == SearchKind.SDK_SK_STREETBYNAME)) { if (index >= 0 && index < mStreetResults.size()) result = mStreetResults.get(index); } else if (mHNRResults != null && (type == SearchKind.SDK_SK_HNR)) { if (index >= 0 && index < mHNRResults.size()) result = mHNRResults.get(index); } return result; } public void resetTownSearch() { mTownResults = null; } public void resetStreetSearch() { mStreetResults = null; } public void resetHNRSearch() { mHNRResults = null; } }
ResultListActivity
This activity has a text input field at the top and will show search results in a listview. The SearchActivity will send the expected type of search in a bundle and the ResultListActivity will call the models appropriate searches when the edit text changes. When a result in the listview is clicked, the chosen result is packaged in a bundle and sent back to the SearchActivity.
package com.ptvag.navigation.tutorial; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.text.Editable; import android.text.TextWatcher; import android.view.View; import android.widget.AdapterView; import android.widget.EditText; import android.widget.ListView; import com.ptvag.navigation.sdk.SearchResult; import com.ptvag.navigation.sdk.SearchKind; public class ResultListActivity extends AppCompatActivity { private SearchKind mType; private int mCc; private SearchAdapter mItemsAdapter; private SearchResult mTownResult; private SearchResult mStreetResult; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_result_list); ListView listView = (ListView) findViewById(R.id.listView); Intent intent = getIntent(); Bundle bundle = intent.getExtras(); if(bundle != null) { int type = bundle.getInt("type"); mType = SearchKind.values()[type]; mCc = bundle.getInt("cc", 0); // get the last clicked result from the SearchActivity (may be null pointers) mTownResult = bundle.getParcelable("town_result"); mStreetResult = bundle.getParcelable("street_result"); // reset all former searches Application.getSearchModel().resetTownSearch(); Application.getSearchModel().resetStreetSearch(); Application.getSearchModel().resetHNRSearch(); mItemsAdapter = new SearchAdapter(this, android.R.layout.simple_list_item_1, Application.getSearchModel(), mType); listView.setAdapter(mItemsAdapter); } listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { Intent returnIntent = new Intent(); Bundle bundle = new Bundle(); // when an item was clicked, we retrieve the corresponding result and send it back to // the SearchActivity to allow showing the name of the found result on the search button SearchResult result = Application.getSearchModel().getResult(i, mType); bundle.putParcelable("result", result); returnIntent.putExtras(bundle); setResult(Activity.RESULT_OK, returnIntent); finish(); } }); EditText editText = (EditText) findViewById(R.id.editText); editText.addTextChangedListener(new TextWatcher() { public void afterTextChanged(Editable s) {} public void beforeTextChanged(CharSequence s, int start, int count, int after) {} public void onTextChanged(CharSequence s, int start, int before, int count) { onSearch(s.toString()); } }); } private void onSearch(String name) { if(mType == SearchKind.SDK_SK_TOWNBYNAME || mType == SearchKind.SDK_SK_TOWNBYNAME_SORTED) { Application.getSearchModel().searchTown(name, mCc); } else if(mType == SearchKind.SDK_SK_STREETBYNAME && mTownResult != null) { Application.getSearchModel().searchStreet(name, mTownResult); } else if(mType == SearchKind.SDK_SK_HNR && mTownResult != null && mStreetResult != null) { Application.getSearchModel().searchHNR(name, mTownResult, mStreetResult); } mItemsAdapter.notifyDataSetChanged(); } }
Add this to the created activity_result_list.xml:
<EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:inputType="textPersonName" android:text="" android:ems="10" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:id="@+id/editText" android:layout_alignParentRight="true" android:layout_alignParentEnd="true"/> <ListView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/editText" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:id="@+id/listView" android:layout_marginTop="12dp"/>
SearchAdapter
The SearchAdapter uses the SearchModels count() and getResult() methods to feed the Listview with the search results.
public class SearchAdapter extends ArrayAdapter<SearchResult> { protected final Activity mContext; protected SearchModel mModel; protected SearchKind mType; public SearchAdapter(Context context, int textViewResourceId, SearchModel model, SearchKind type) { super(context, textViewResourceId); this.mContext = (Activity) context; this.mModel = model; this.mType = type; } @Override public int getCount() { int cnt = mModel.count(mType); return cnt; } @Override public SearchResult getItem(int position) { return mModel.getResult(position, mType); } @Override public long getItemId(int arg0) { if(mModel.count(mType) > 0) return arg0; else return 0; } @Override public View getView(int position, View convertView, ViewGroup viewGroup) { if(mModel.count(mType) < 1) return null; View v = convertView; if (v == null) { LayoutInflater layoutInflater = (LayoutInflater)mContext.getLayoutInflater(); v = layoutInflater.inflate(R.layout.row_search_result, null, true); } SearchResult result; result = mModel.getResult(position, mType); String name = result.getName(); TextView text = (TextView) v.findViewById(R.id.searchResultItem); text.setText(name); return v; } }
The SearchAdapter needs a layout for the returned listview row, so create an xml file called row_search_result.xml in the res directory and put the following code in it:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:orientation="vertical" > <TextView android:id="@+id/searchResultItem" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_vertical" android:padding="15dp" android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium" android:singleLine="true"/> </LinearLayout>
CountryAdapter
To allow searching in different Countries we implement a CountryAdapter consisting of all countries in all installed maps. It iterates over all availableMaps and extracts all countries in them. If a map has a DetailLevel of 1 it consist only of the major roads and will be sorted to the end of the countries. Countries can be federal states in some situations and are represented by PtvAlpha country codes. The town search needs the country code as a numerical ptvCode. We use NavigationSDK.transformCountryCodeToPtvCode
to convert the code.
package com.ptvag.navigation.tutorial; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; import com.ptvag.navigation.sdk.CountryCodeFormat; import com.ptvag.navigation.sdk.MapInformation; import com.ptvag.navigation.sdk.NavigationSDK; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class CountryAdapter extends ArrayAdapter<CountryAdapter.Country> { public class Country { public Country(int ptvCode, boolean isMajorRoad, int resId, int mapId) { this.ptvCode = ptvCode; this.isMajorRoad = isMajorRoad; this.resId = resId; this.mapId = mapId; } public int getPtvCode() { return ptvCode; } public boolean isMajorRoad() { return isMajorRoad; } public int getResId() { return resId; } public int getMapId() { return mapId; } private int ptvCode; private boolean isMajorRoad; private int resId; private int mapId; } List<Country> countries = new ArrayList<>(); Context context; public CountryAdapter(final Context context, int textViewResourceId) { super(context, textViewResourceId); this.context = context.getApplicationContext(); int i = 0; for (MapInformation info : NavigationSDK.getAvailableMaps()) { for (String ptvAlpha : info.getCountries()) { int ptvCode = NavigationSDK.transformCountryCodeToPtvCode(CountryCodeFormat.PtvAlpha, ptvAlpha); String resName = "country_" + ptvCode; int stringId = context.getResources().getIdentifier(resName, "string", context.getPackageName()); countries.add(new Country(ptvCode, info.getDetailLevel() == 1, stringId, i)); } ++i; } Collections.sort(countries, new Comparator<Country>() { @Override public int compare(Country o1, Country o2) { if (o1.isMajorRoad() == o2.isMajorRoad()) { return context.getString(o1.getResId()).compareTo(context.getString(o2.getResId())); } else { if (o1.isMajorRoad()) { return 1; } else { return -1; } } } }); } @Override public int getCount() { return countries.size(); } @Override public Country getItem(int position) { return countries.get(position); } @Override public long getItemId(int arg0) { if(getCount() > 0) return arg0; else return 0; } @Override public View getDropDownView(int position, View convertView, ViewGroup parent) { return getCustomView(position, convertView, parent); } @Override public View getView(int position, View convertView, ViewGroup parent) { return getCustomView(position, convertView, parent); } public View getCustomView(int position, View convertView, ViewGroup parent) { if(getCount() < 1) return null; View v = convertView; if (v == null) { LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE ); v = layoutInflater.inflate(R.layout.row_search_country, null, true); } TextView text = (TextView) v.findViewById(R.id.countries_row_text); Country country = getItem(position); text.setText(country.getResId()); int drawableId = R.drawable.flag_motorway; if (!country.isMajorRoad()) { String isoCode = NavigationSDK.transformPtvCodeToCountryCode(CountryCodeFormat.Iso2, country.getPtvCode()).toLowerCase(); drawableId = context.getResources().getIdentifier("flag_" + isoCode, "drawable", context.getPackageName()); } ImageView image = (ImageView) v.findViewById(R.id.countries_row_image); image.setImageResource(drawableId); return v; } }
The CountryAdapter needs a layout for the returned listview row, so create an xml file called row_search_country.xml in the res directory and put the following code in it:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="?android:attr/listPreferredItemHeight" android:orientation="horizontal" > <ImageView android:id="@+id/countries_row_image" android:layout_width="wrap_content" android:layout_height="match_parent" android:minWidth="30dp" android:src="@drawable/flag_de" android:scaleType="centerInside" android:paddingLeft="16dp" /> <TextView android:id="@+id/countries_row_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_vertical" android:padding="16dp" android:textAppearance="@style/TextAppearance.AppCompat.Large" android:textColor="#fff" /> </LinearLayout>
SearchActivity
The SearchActivity is the central place for our search.
When clicking one of the buttons, the ResultListActivity will be started in the appropriate search mode (town, street or house number). The CountrySpinner allows us to change the map by country to search in the according country. It shows the values from the implemented CountryAdapter. The ResultListActivity
will be started with startActivityForResult()
. When the ResultListActivity sends back the corresponding result, the onActivityResult()
will be called and
the SearchActivity modifies the text of the buttons out of the result. The current result will be shown on the MapView. The zoom factor depends on the search
type. You also can pan and zoom the MapView manually.
Add the following to the created activity_search.xml:
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_search" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="16dp" android:paddingLeft="16dp" android:paddingRight="16dp" android:paddingTop="16dp" tools:context="com.ptvag.navigation.tutorial.SearchActivity"> <LinearLayout android:id="@+id/search" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <Spinner android:id="@+id/countrySpinner" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="8dp"/> <Button android:text="@string/town" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/buttonTown" android:onClick="onTownClicked"/> <Button android:text="@string/street" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/buttonStreet" android:onClick="onStreetClicked"/> <Button android:text="@string/house_number" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/buttonHNR" android:onClick="onHNRClicked"/> <com.ptvag.navigation.tutorial.MapView android:id="@+id/map" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="4dp"/> </LinearLayout> </android.support.design.widget.CoordinatorLayout>
And add the strings to the strings.xml (which can be found in the value directory):
<string name="town">Town</string> <string name="street">Street</string> <string name="house_number">House number</string>
Also add a list of countries for the CountrySpinner to your strings.xml. You notice that countries can also be federal states in some situations and are represented by a numerical Ptv country code.
<string name="country_1">Czech Republic</string> <string name="country_101">Alabama</string> <string name="country_102">Alaska</string> <string name="country_104">Arizona</string> <string name="country_105">Arkansas</string> <string name="country_106">California</string> <string name="country_108">Colorado</string> <string name="country_109">Connecticut</string> <string name="country_11">Estonia</string> <string name="country_110">Delaware</string> <string name="country_111">District of Columbia</string> <string name="country_112">Florida</string> <string name="country_113">Georgia</string> <string name="country_115">Hawaii</string> <string name="country_116">Idaho</string> <string name="country_117">Illinois</string> <string name="country_118">Indiana</string> <string name="country_119">Iowa</string> <string name="country_120">Kansas</string> <string name="country_121">Kentucky</string> <string name="country_122">Louisiana</string> <string name="country_123">Maine</string> <string name="country_124">Maryland</string> <string name="country_125">Massachusetts</string> <string name="country_126">Michigan</string> <string name="country_127">Minnesota</string> <string name="country_128">Mississippi</string> <string name="country_129">Missouri</string> <string name="country_13">Latvia</string> <string name="country_130">Montana</string> <string name="country_131">Nebraska</string> <string name="country_132">Nevada</string> <string name="country_133">New Hampshire</string> <string name="country_134">New Jersey</string> <string name="country_135">New Mexico</string> <string name="country_136">New York</string> <string name="country_137">North Carolina</string> <string name="country_138">North Dakota</string> <string name="country_139">Ohio</string> <string name="country_14">Lithuania</string> <string name="country_140">Oklahoma</string> <string name="country_141">Oregon</string> <string name="country_142">Pennsylvania</string> <string name="country_144">Rhode Island</string> <string name="country_145">South Carolina</string> <string name="country_146">South Dakota</string> <string name="country_147">Tennessee</string> <string name="country_148">Texas</string> <string name="country_149">Utah</string> <string name="country_15">Moldova, Republic of</string> <string name="country_150">Vermont</string> <string name="country_151">Virginia</string> <string name="country_153">Washington</string> <string name="country_154">West Virginia</string> <string name="country_155">Wisconsin</string> <string name="country_156">Wyoming</string> <string name="country_16">Russia</string> <string name="country_17">Ukraine</string> <string name="country_18">Belarus</string> <string name="country_2">Slovakia</string> <string name="country_200">Canada</string> <string name="country_299">Greenland</string> <string name="country_30">Greece</string> <string name="country_31">Netherlands</string> <string name="country_32">Belgium</string> <string name="country_33">France</string> <string name="country_34">Spain</string> <string name="country_36">Hungary</string> <string name="country_382">Montenegro</string> <string name="country_39">Italy</string> <string name="country_40">Romania</string> <string name="country_41">Switzerland</string> <string name="country_43">Austria</string> <string name="country_44">Great Britain</string> <string name="country_45">Denmark</string> <string name="country_46">Sweden</string> <string name="country_47">Norway</string> <string name="country_48">Poland</string> <string name="country_49">Germany</string> <string name="country_50">Gibraltar</string> <string name="country_51">Portugal</string> <string name="country_52">Luxembourg</string> <string name="country_53">Ireland</string> <string name="country_54">Iceland</string> <string name="country_55">Albania</string> <string name="country_56">Malta</string> <string name="country_57">Cyprus</string> <string name="country_58">Finland</string> <string name="country_59">Bulgaria</string> <string name="country_62">Andorra</string> <string name="country_64">New Zealand</string> <string name="country_7">San Marino</string> <string name="country_75">Liechtenstein</string> <string name="country_741">Western Australia</string> <string name="country_742">Queensland</string> <string name="country_743">New South Wales</string> <string name="country_744">Victoria</string> <string name="country_745">South Australia</string> <string name="country_746">Tasmania</string> <string name="country_747">Northern Territory</string> <string name="country_748">Capital Territory</string> <string name="country_752">Mexico</string> <string name="country_755">Brazil</string> <string name="country_761">Australia</string> <string name="country_762">Indonesia</string> <string name="country_81">Serbia</string> <string name="country_85">Croatia</string> <string name="country_86">Slovenia</string> <string name="country_87">Bosnia</string> <string name="country_89">Macedonia</string> <string name="country_90">Turkey</string> <string name="country_93">Monaco</string> <string name="country_96">Vatican City</string> <string name="country_98">Faroe Islands</string>
Implement the SearchActivity:
package com.ptvag.navigation.tutorial; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.Button; import android.widget.Spinner; import android.support.v7.app.AppCompatActivity; import com.ptvag.navigation.sdk.GeoPosition; import com.ptvag.navigation.sdk.NavigationSDK; import com.ptvag.navigation.sdk.Position; import com.ptvag.navigation.sdk.SearchResult; import com.ptvag.navigation.sdk.SearchKind; import java.util.ArrayList; import java.util.List; public class SearchActivity extends AppCompatActivity { private MapView mapView; private Button townButton; private Button streetButton; private Button hnrButton; private SearchResult mCurrentTownResult; private SearchResult mCurrentStreetResult; private SearchResult mCurrentHNRResult; private Spinner mCountrySpinner; private int pinImageID; private CountryAdapter mAdapter; private CountryAdapter.Country mSelectedCountry; @Override protected void onCreate(Bundle savedInstanceState) { pinImageID = -1; super.onCreate(savedInstanceState); setContentView(R.layout.activity_search); mapView = (MapView)findViewById(R.id.map); townButton = (Button) findViewById(R.id.buttonTown); streetButton = (Button) findViewById(R.id.buttonStreet); hnrButton = (Button) findViewById(R.id.buttonHNR); mCountrySpinner = (Spinner)findViewById( R.id.countrySpinner ); GeoPosition mapViewPosition = new Position(934177, 6268747).toGeoPosition(); int mapViewScale = 5000; mapView.setCenter(mapViewPosition); // Karlsruhe/Germany mapView.setScale(mapViewScale); mAdapter = new CountryAdapter( this, R.layout.row_search_country); mCountrySpinner.setAdapter( mAdapter ); mCountrySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { CountryAdapter.Country country = mAdapter.getItem(position); NavigationSDK.changeMap(country.getMapId()); mSelectedCountry = country; resetAllSearches(); } @Override public void onNothingSelected(AdapterView<?> parent) { } }); mCountrySpinner.setSelection(0); } private void resetAllSearches() { Application.getSearchModel().resetTownSearch(); Application.getSearchModel().resetStreetSearch(); Application.getSearchModel().resetHNRSearch(); townButton.setText(R.string.town); streetButton.setText(R.string.street); hnrButton.setText(R.string.house_number); streetButton.setEnabled(false); hnrButton.setEnabled(false); } @Override protected void onResume() { super.onResume(); mapView.resume(); // tell the MapView the activity is resumed } @Override protected void onPause() { super.onPause(); mapView.finish(); } public void onTownClicked(View view) { Intent intent = new Intent(this, ResultListActivity.class); Bundle bundle = new Bundle(); SearchKind type = SearchKind.SDK_SK_TOWNBYNAME_SORTED; bundle.putInt("type", type.getId()); bundle.putInt("cc", mSelectedCountry.getPtvCode()); intent.putExtras(bundle); startActivityForResult(intent, 1); } public void onStreetClicked(View view) { Intent intent = new Intent(this, ResultListActivity.class); Bundle bundle = new Bundle(); SearchKind type = SearchKind.SDK_SK_STREETBYNAME; bundle.putInt("type", type.getId()); bundle.putParcelable("town_result", mCurrentTownResult); intent.putExtras(bundle); startActivityForResult(intent, 2); } public void onHNRClicked(View view) { Intent intent = new Intent(this, ResultListActivity.class); Bundle bundle = new Bundle(); SearchKind type = SearchKind.SDK_SK_HNR; bundle.putInt("type", type.getId()); bundle.putParcelable("town_result", mCurrentTownResult); bundle.putParcelable("street_result", mCurrentStreetResult); intent.putExtras(bundle); startActivityForResult(intent, 3); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { String name; int mapViewScale = 5000; if (resultCode == Activity.RESULT_OK) { Bundle res = data.getExtras(); if(res != null) { SearchResult result = res.getParcelable("result"); if (result != null) { name = result.getName(); switch (requestCode) { case 1: // town search townButton.setText(name); streetButton.setText(R.string.street); hnrButton.setText(R.string.house_number); streetButton.setEnabled(true); hnrButton.setEnabled(false); mCurrentTownResult = result; mCurrentStreetResult = null; mCurrentHNRResult = null; mapViewScale = 2500; break; case 2: // street search streetButton.setText(name); hnrButton.setText(R.string.house_number); hnrButton.setEnabled(true); mCurrentStreetResult = result; mCurrentHNRResult = null; mapViewScale = 200; break; case 3: // house number search hnrButton.setText(name); mCurrentHNRResult = result; mapViewScale = 100; break; default: } if (pinImageID < 0) pinImageID = NavigationSDK.addImage("pin.png", result.getPosition()); else NavigationSDK.positionImage(pinImageID, result.getPosition()); mapView.setCenter(result.getPosition().toGeoPosition()); mapView.setScale(mapViewScale); } } } } }