[Core sample] improved ui

This commit is contained in:
Alexey Kulish 2016-06-25 11:43:54 +03:00
parent a51d0d864a
commit 3f356500e0
8 changed files with 206 additions and 77 deletions

View file

@ -7,30 +7,51 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:gravity="center_vertical"
android:orientation="horizontal">
android:orientation="vertical">
<ImageButton
android:id="@+id/clearButton"
style="@style/Widget.AppCompat.ActionButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:contentDescription="@string/shared_string_close"
android:src="@drawable/ic_action_remove_dark"/>
<EditText
android:id="@+id/searchEditText"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:background="@null"
android:hint="@string/search_hint"
android:layout_height="56dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageButton
android:id="@+id/clearButton"
style="@style/Widget.AppCompat.ActionButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:contentDescription="@string/shared_string_close"
android:src="@drawable/ic_action_remove_dark"/>
<EditText
android:id="@+id/searchEditText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:background="@null"
android:gravity="center_vertical"
android:hint="@string/search_hint"
android:lines="1"
android:textColor="@color/titleTextColor"
tools:text="Search request"/>
</LinearLayout>
<TextView
android:id="@+id/searchDetailsText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="64dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
android:gravity="center_vertical"
android:lines="1"
android:textColor="@color/titleTextColor"
tools:text="Search request"/>
android:visibility="gone"
tools:text="City • Street"
tools:visibility="visible"/>
</LinearLayout>
<FrameLayout
@ -41,10 +62,10 @@
<net.osmand.core.android.AtlasMapRendererView
android:id="@+id/mapRendererView"
android:focusable="true"
android:focusableInTouchMode="true"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"/>
<FrameLayout
android:layout_width="wrap_content"
@ -111,8 +132,8 @@
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="true"
android:background="@color/listBackgroundColor"
android:drawSelectorOnTop="true"
android:visibility="gone"/>
</FrameLayout>

View file

@ -47,9 +47,12 @@ import net.osmand.core.samples.android.sample1.adapters.SearchListPositionItem;
import net.osmand.core.samples.android.sample1.search.SearchAPI;
import net.osmand.core.samples.android.sample1.search.SearchAPI.SearchApiCallback;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject.SearchObjectType;
import net.osmand.core.samples.android.sample1.search.tokens.SearchToken;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class MainActivity extends Activity {
private static final String TAG = "OsmAndCoreSample";
@ -81,8 +84,11 @@ public class MainActivity extends Activity {
private MultiTouchSupport multiTouchSupport;
private SearchAPI searchAPI;
private EditText searchEditText;
private TextView searchDetailsText;
private ListView searchListView;
private SearchListAdapter adapter;
private String queryText = "";
private final static int MAX_SEARCH_RESULTS_CORE = 300;
private final static int MAX_SEARCH_RESULTS_IU = 50;
@ -104,6 +110,34 @@ public class MainActivity extends Activity {
private static final String PREF_MAP_ZOOM = "MAP_ZOOM";
private static final String PREF_MAP_ELEVATION_ANGLE = "MAP_ELEVATION_ANGLE";
private SearchApiCallback intermediateSearchCallback = new SearchApiCallback() {
@Override
public void onSearchFinished(List<SearchObject> searchObjects) {
processSearchResult(searchObjects);
}
};
private SearchApiCallback coreSearchCallback = new SearchApiCallback() {
@Override
public void onSearchFinished(List<SearchObject> searchObjects) {
processSearchResult(searchObjects);
StringBuilder sb = new StringBuilder();
Map<SearchObjectType, SearchToken> objectTokensMap = searchAPI.getObjectTokens();
for (SearchToken token : objectTokensMap.values()) {
if (sb.length() > 0) {
sb.append("");
}
sb.append(token.getSearchObject().getName(MapUtils.LANGUAGE));
}
if (sb.length() == 0) {
searchDetailsText.setVisibility(View.GONE);
} else {
searchDetailsText.setText(sb.toString());
searchDetailsText.setVisibility(View.VISIBLE);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -205,7 +239,7 @@ public class MainActivity extends Activity {
searchAPI = new SearchAPI(obfsCollection, MapUtils.LANGUAGE);
final EditText searchEditText = (EditText) findViewById(R.id.searchEditText);
searchEditText = (EditText) findViewById(R.id.searchEditText);
searchEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@ -217,7 +251,11 @@ public class MainActivity extends Activity {
@Override
public void afterTextChanged(Editable s) {
runSearch(getScreenCenter31(), getScreenBounds31(), s.toString());
String newQueryText = s.toString();
if (!queryText.equalsIgnoreCase(newQueryText)) {
queryText = newQueryText;
runSearch(getScreenCenter31(), getScreenBounds31(), queryText);
}
}
});
searchEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@ -232,6 +270,8 @@ public class MainActivity extends Activity {
}
});
searchDetailsText = (TextView) findViewById(R.id.searchDetailsText);
ImageButton clearButton = (ImageButton) findViewById(R.id.clearButton);
clearButton.setOnClickListener(new View.OnClickListener() {
@Override
@ -249,15 +289,18 @@ public class MainActivity extends Activity {
searchListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
hideSearchList();
mapView.requestFocus();
SearchListItem item = adapter.getItem(position);
if (item instanceof SearchListPositionItem) {
SearchListPositionItem positionItem = (SearchListPositionItem) item;
PointI target = Utilities.convertLatLonTo31(
new LatLon(positionItem.getLatitude(), positionItem.getLongitude()));
setTarget(target);
setZoom(17f);
SearchObject searchObject = item.getSearchObject();
if (searchObject.getType() == SearchObjectType.POI
|| searchObject.getType() == SearchObjectType.BUILDING
|| searchObject.getType() == SearchObjectType.COORDINATES) {
// show on map
hideSearchList();
mapView.requestFocus();
showOnMap((SearchListPositionItem) item);
} else {
// complete search query with selected object
completeQueryWithObject(item.getSearchObject());
}
}
});
@ -290,6 +333,13 @@ public class MainActivity extends Activity {
return (SampleApplication) getApplication();
}
private void showOnMap(SearchListPositionItem positionItem) {
PointI target = Utilities.convertLatLonTo31(
new LatLon(positionItem.getLatitude(), positionItem.getLongitude()));
setTarget(target);
setZoom(17f);
}
private PointI getScreenCenter31() {
PointI point = new PointI();
mapView.getLocationFromScreenPoint(new PointI(mapView.getWidth() / 2, mapView.getHeight() / 2), point);
@ -410,20 +460,14 @@ public class MainActivity extends Activity {
searchAPI.setSearchLocation31(position31);
searchAPI.setObfAreaFilter(bounds31);
searchAPI.startSearch(keyword, MAX_SEARCH_RESULTS_CORE,
// Intermediate search callback
new SearchApiCallback() {
@Override
public void onSearchFinished(List<SearchObject> searchObjects) {
processSearchResult(searchObjects);
}
},
// Core search callback
new SearchApiCallback() {
@Override
public void onSearchFinished(List<SearchObject> searchObjects) {
processSearchResult(searchObjects);
}
});
intermediateSearchCallback, coreSearchCallback);
}
private void completeQueryWithObject(SearchObject searchObject) {
queryText = searchAPI.completeSearch(searchObject, MAX_SEARCH_RESULTS_CORE,
intermediateSearchCallback, coreSearchCallback);
searchEditText.setText(queryText);
searchEditText.setSelection(queryText.length());
}
private void processSearchResult(List<SearchObject> searchObjects) {

View file

@ -36,7 +36,7 @@ public class SearchListItem {
return null;
}
protected SearchObject getSearchObject() {
public SearchObject getSearchObject() {
return searchObject;
}

View file

@ -6,6 +6,7 @@ import net.osmand.core.jni.AreaI;
import net.osmand.core.jni.ObfsCollection;
import net.osmand.core.jni.PointI;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject.SearchObjectType;
import net.osmand.core.samples.android.sample1.search.requests.CoreSearchRequest;
import net.osmand.core.samples.android.sample1.search.requests.IntermediateSearchRequest;
import net.osmand.core.samples.android.sample1.search.requests.SearchRequest;
@ -13,6 +14,7 @@ import net.osmand.core.samples.android.sample1.search.tokens.SearchToken;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class SearchAPI {
@ -51,7 +53,7 @@ public class SearchAPI {
public SearchAPI(@NonNull ObfsCollection obfsCollection, String lang) {
this.obfsCollection = obfsCollection;
this.executor = new SearchRequestExecutor();
this.searchString = new SearchString();
this.searchString = new SearchString(lang);
this.lang = lang;
}
@ -107,11 +109,31 @@ public class SearchAPI {
this.searchObjects = searchObjects;
}
public Map<SearchObjectType, SearchToken> getObjectTokens() {
return searchString.getObjectTokens();
}
public void startSearch(String query, int maxSearchResults,
SearchApiCallback intermediateSearchCallback,
SearchApiCallback coreSearchCallback) {
searchString.setQueryText(query);
startSearchInternal(maxSearchResults, intermediateSearchCallback, coreSearchCallback);
}
public String completeSearch(SearchObject searchObject, int maxSearchResults,
SearchApiCallback intermediateSearchCallback,
SearchApiCallback coreSearchCallback) {
searchString.completeQuery(searchObject);
startSearchInternal(maxSearchResults, intermediateSearchCallback, coreSearchCallback);
return searchString.getQueryText();
}
private void startSearchInternal(int maxSearchResults,
SearchApiCallback intermediateSearchCallback,
SearchApiCallback coreSearchCallback) {
SearchScope searchScope = new SearchScope(this);
IntermediateSearchRequest intermediateSearchRequest = null;
if (searchObjects != null && !searchObjects.isEmpty()) {

View file

@ -17,7 +17,6 @@ import net.osmand.core.samples.android.sample1.search.objects.StreetGroupSearchO
import net.osmand.core.samples.android.sample1.search.objects.StreetSearchObject;
import net.osmand.core.samples.android.sample1.search.tokens.ObjectSearchToken;
import net.osmand.core.samples.android.sample1.search.tokens.SearchToken;
import net.osmand.util.Algorithms;
import java.util.Collections;
import java.util.Comparator;
@ -125,7 +124,7 @@ public class SearchScope {
});
if (token.getType() == SearchToken.TokenType.NAME_FILTER
&& !Algorithms.isEmpty(token.getQueryText())) {
&& !token.hasEmptyQuery()) {
newToken = new ObjectSearchToken(token, searchObjects.get(0));
}
}

View file

@ -1,13 +1,18 @@
package net.osmand.core.samples.android.sample1.search;
import android.support.annotation.NonNull;
import net.osmand.core.samples.android.sample1.MapUtils;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject.SearchObjectType;
import net.osmand.core.samples.android.sample1.search.tokens.NameFilterSearchToken;
import net.osmand.core.samples.android.sample1.search.tokens.ObjectSearchToken;
import net.osmand.core.samples.android.sample1.search.tokens.SearchToken;
import net.osmand.core.samples.android.sample1.search.tokens.SearchToken.TokenType;
import net.osmand.util.Algorithms;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -15,12 +20,14 @@ public class SearchString {
private String queryText = "";
private List<SearchToken> tokens = new ArrayList<>();
private String lang;
public SearchString() {
public SearchString(String lang) {
this.lang = lang;
}
public SearchString copy() {
SearchString res = new SearchString();
SearchString res = new SearchString(lang);
res.queryText = queryText;
res.tokens = new ArrayList<>(tokens);
return res;
@ -91,6 +98,23 @@ public class SearchString {
this.queryText = queryText;
}
public void completeQuery(@NonNull SearchObject searchObject) {
String newQueryText;
String objectName = searchObject.getName(lang);
int startIndex;
SearchToken lastToken = getLastToken();
if (lastToken.hasEmptyQuery()) {
startIndex = queryText.length();
newQueryText = queryText + objectName + " ";
} else {
startIndex = lastToken.getStartIndex();
newQueryText = queryText.substring(0, startIndex) + objectName + " ";
}
ObjectSearchToken token = new ObjectSearchToken(startIndex, objectName, searchObject);
tokens.set(tokens.size() - 1, token);
queryText = newQueryText;
}
private boolean endWithDelimeter(String text) {
return !Algorithms.isEmpty(text) && isDelimiterChar(text.charAt(text.length() - 1));
}
@ -104,13 +128,13 @@ public class SearchString {
return c == ',' || c == ' ';
}
public SearchToken getNextNameFilterToken() {
SearchToken res = null;
public NameFilterSearchToken getNextNameFilterToken() {
NameFilterSearchToken res = null;
if (!tokens.isEmpty()) {
for (int i = tokens.size() - 1; i >= 0; i--) {
SearchToken token = tokens.get(i);
if (token.getType() == TokenType.NAME_FILTER) {
res = token;
res = (NameFilterSearchToken) token;
} else {
break;
}
@ -126,8 +150,19 @@ public class SearchString {
return null;
}
public boolean hasNameFilterTokens() {
return getNextNameFilterToken() != null;
public ObjectSearchToken getLastObjectToken() {
ObjectSearchToken res = null;
if (!tokens.isEmpty()) {
for (int i = tokens.size() - 1; i >= 0; i--) {
SearchToken token = tokens.get(i);
if (token.getType() == TokenType.SEARCH_OBJECT) {
res = (ObjectSearchToken) token;
} else {
break;
}
}
}
return res;
}
public boolean replaceToken(SearchToken oldToken, SearchToken newToken) {
@ -140,7 +175,7 @@ public class SearchString {
}
public Map<SearchObjectType, SearchToken> getObjectTokens() {
Map<SearchObjectType, SearchToken> map = new HashMap<>();
Map<SearchObjectType, SearchToken> map = new LinkedHashMap<>();
for (SearchToken token : tokens) {
if (token.getType() == TokenType.SEARCH_OBJECT) {
map.put(token.getSearchObject().getType(), token);
@ -151,7 +186,7 @@ public class SearchString {
public static void main(String[] args){
//test
SearchString searchString = new SearchString();
SearchString searchString = new SearchString(MapUtils.LANGUAGE);
searchString.setQueryText("cit");
searchString.setQueryText("city");
searchString.setQueryText("city ");

View file

@ -19,8 +19,9 @@ import net.osmand.core.samples.android.sample1.search.objects.PoiSearchObject;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
import net.osmand.core.samples.android.sample1.search.objects.SearchObjectsHelper;
import net.osmand.core.samples.android.sample1.search.objects.SearchPositionObject;
import net.osmand.core.samples.android.sample1.search.tokens.NameFilterSearchToken;
import net.osmand.core.samples.android.sample1.search.tokens.ObjectSearchToken;
import net.osmand.core.samples.android.sample1.search.tokens.SearchToken;
import net.osmand.util.Algorithms;
import java.util.ArrayList;
import java.util.List;
@ -84,10 +85,9 @@ public class CoreSearchRequest extends SearchRequest {
SearchString searchString = searchScope.getSearchString();
SearchToken lastToken = searchString.getLastToken();
SearchToken token = searchString.getNextNameFilterToken();
NameFilterSearchToken token = searchString.getNextNameFilterToken();
while (token != null && !cancelled) {
if (token.getType() == SearchToken.TokenType.NAME_FILTER
&& !Algorithms.isEmpty(token.getQueryText())) {
if (!token.hasEmptyQuery()) {
res = doCoreSearch(token);
}
if (token != lastToken) {
@ -97,11 +97,26 @@ public class CoreSearchRequest extends SearchRequest {
}
}
if (lastToken == null || lastToken.hasEmptyQuery()) {
// todo 2.4
// 2.4 Search considered to be complete if there no NF in the end (not finished or not regonized objects)
ObjectSearchToken lastObjectToken = searchString.getLastObjectToken();
if (lastObjectToken == null) {
// Last object = [] - none. We display list of poi categories (recents separate tab)
} else {
// Last object - poi category/poi filter/poi type. Display: poi filters (if it is poi category & pois around location (if it is specified in query by any previous object) + Search more radius
// For example: Leiden ice hockey, we display all ice hockey around Leiden
// Last object - City. Display (list of streets could be quite long)
// Last object - Street. Display building and intersetcting street
// Last object - Postcode. Display building and streets
// Last object - Building/POI - object is found
}
}
return res;
}
private List<SearchObject> doCoreSearch(@NonNull SearchToken token) {
System.out.println("=== Start search");
amenityResultsCounter = 0;
addressResultsCounter = 0;
@ -125,7 +140,6 @@ public class CoreSearchRequest extends SearchRequest {
if (searchScope.processPoiSearchObject(amenitySearchItem)) {
searchObjects.add(amenitySearchItem);
}
System.out.println("Poi found === " + amenitySearchItem.toString());
amenityResultsCounter++;
}
};
@ -148,7 +162,6 @@ public class CoreSearchRequest extends SearchRequest {
if (searchScope.processAddressSearchObject(addressSearchObject)) {
searchObjects.add(addressSearchObject);
}
System.out.println("Address found === " + addressSearchObject.toString());
addressResultsCounter++;
}
}
@ -177,8 +190,6 @@ public class CoreSearchRequest extends SearchRequest {
}
}
System.out.println("=== Finish search");
return searchObjects;
}

View file

@ -1,6 +1,7 @@
package net.osmand.core.samples.android.sample1.search.tokens;
import net.osmand.core.samples.android.sample1.search.objects.SearchObject;
import net.osmand.util.Algorithms;
public abstract class SearchToken {
@ -29,10 +30,6 @@ public abstract class SearchToken {
return startIndex;
}
public void setStartIndex(int startIndex) {
this.startIndex = startIndex;
}
public String getQueryText() {
return queryText;
}
@ -41,11 +38,11 @@ public abstract class SearchToken {
return startIndex + queryText.length() - 1;
}
public int getQueryTextLenght() {
return queryText.length();
}
public SearchObject getSearchObject() {
return searchObject;
}
public boolean hasEmptyQuery() {
return Algorithms.isEmpty(queryText);
}
}