package net.osmand.plus.activities.search; import java.io.InputStream; import java.net.URLConnection; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import java.util.Locale; import net.osmand.PlatformUtil; import net.osmand.data.LatLon; import net.osmand.data.PointDescription; import net.osmand.osm.io.NetworkUtils; import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.Version; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.search.SearchActivity.SearchActivityChild; import net.osmand.plus.dialogs.DirectionsDialogs; import net.osmand.util.Algorithms; import net.osmand.util.MapUtils; import org.apache.commons.logging.Log; import org.xmlpull.v1.XmlPullParser; import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.view.MenuItemCompat; import android.support.v7.widget.PopupMenu; import android.util.Xml; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MenuItem.OnMenuItemClickListener; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; public class SearchAddressOnlineFragment extends Fragment implements SearchActivityChild, OnItemClickListener { private LatLon location; private final static Log log = PlatformUtil.getLog(SearchAddressOnlineFragment.class); private static PlacesAdapter adapter = null; private OsmandSettings settings; private View view; private EditText searchText; @Override public void onCreateOptionsMenu(Menu onCreate, MenuInflater inflater) { Menu menu = onCreate; if(getActivity() instanceof SearchActivity) { menu = ((SearchActivity) getActivity()).getClearToolbar(true).getMenu(); } MenuItem menuItem = menu.add(0, 1, 0, R.string.search_offline_clear_search); MenuItemCompat.setShowAsAction(menuItem, MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT); menuItem = menuItem.setIcon(R.drawable.ic_action_gremove_dark); menuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { searchText.setText(""); adapter.clear(); return true; } }); if (getActivity() instanceof SearchActivity) { menuItem = menu.add(0, 0, 0, R.string.search_offline_address); MenuItemCompat.setShowAsAction(menuItem, MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT); menuItem = menuItem.setIcon(R.drawable.ic_sdcard); menuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { ((SearchActivity) getActivity()).startSearchAddressOffline(); return true; } }); } } public View onCreateView(android.view.LayoutInflater inflater, android.view.ViewGroup container, Bundle savedInstanceState) { view = inflater.inflate(R.layout.search_address_online, container, false); adapter = new PlacesAdapter(new ArrayList<SearchAddressOnlineFragment.Place>()); settings = ((OsmandApplication) getActivity().getApplication()).getSettings(); searchText = (EditText) view.findViewById(R.id.SearchText); Button searchButton = (Button) view.findViewById(R.id.SearchButton); searchButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.hideSoftInputFromWindow(searchText.getWindowToken(), 0); // Remove keyboard searchPlaces(searchText.getText().toString()); } }); setHasOptionsMenu(true); location = settings.getLastKnownMapLocation(); ListView lv = (ListView) view.findViewById(android.R.id.list); lv.setAdapter(adapter); lv.setOnItemClickListener(this); return view; } @Override public void onResume() { super.onResume(); Intent intent = getActivity().getIntent(); if(intent != null){ double lat = intent.getDoubleExtra(SearchActivity.SEARCH_LAT, 0); double lon = intent.getDoubleExtra(SearchActivity.SEARCH_LON, 0); if(lat != 0 || lon != 0){ adapter.location = new LatLon(lat, lon); } } if (location == null && getActivity() instanceof SearchActivity) { location = ((SearchActivity) getActivity()).getSearchPoint(); } if (location == null) { location = settings.getLastKnownMapLocation(); } locationUpdate(location); } @Override public void locationUpdate(LatLon l) { location = l; if(adapter != null){ adapter.updateLocation(l); } } protected void searchPlaces(final String search) { if(Algorithms.isEmpty(search)){ return; } new AsyncTask<Void, Void, Void>() { List<Place> places = null; String warning = null; protected void onPreExecute() { view.findViewById(R.id.ProgressBar).setVisibility(View.VISIBLE); }; @Override protected Void doInBackground(Void... params) { try { final int deviceApiVersion = android.os.Build.VERSION.SDK_INT; String NOMINATIM_API; if (deviceApiVersion >= android.os.Build.VERSION_CODES.GINGERBREAD) { NOMINATIM_API = "https://nominatim.openstreetmap.org/search"; } else { NOMINATIM_API = "http://nominatim.openstreetmap.org/search"; } final List<Place> places = new ArrayList<Place>(); StringBuilder b = new StringBuilder(); b.append(NOMINATIM_API); //$NON-NLS-1$ b.append("?format=xml&addressdetails=0&accept-language=").append(Locale.getDefault().getLanguage()); //$NON-NLS-1$ b.append("&q=").append(URLEncoder.encode(search, "UTF-8")); //$NON-NLS-1$ log.info("Searching address at : " + b); //$NON-NLS-1$ URLConnection conn = NetworkUtils.getHttpURLConnection(b.toString()); conn.setDoInput(true); conn.setRequestProperty("User-Agent", Version.getFullVersion((OsmandApplication) getActivity().getApplication())); //$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()){ this.places = null; warning = getString(R.string.search_nothing_found); } else { this.places = places; } } catch(Exception e){ log.error("Error searching address", e); //$NON-NLS-1$ warning = getString(R.string.shared_string_io_error) + " : " + e.getMessage(); } return null; } protected void onPostExecute(Void result) { view.findViewById(R.id.ProgressBar).setVisibility(View.INVISIBLE); if(places == null){ Toast.makeText(getActivity(), warning, Toast.LENGTH_LONG).show(); } else { adapter.setPlaces(places); } }; }.execute((Void) null); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Place item = adapter.getItem(position); LatLon location = new LatLon(item.lat, item.lon); settings.setMapLocationToShow(location.getLatitude(), location.getLongitude(), Math.max(15, settings.getLastKnownMapZoom()), new PointDescription(PointDescription.POINT_TYPE_ADDRESS, item.displayName), true, item); //$NON-NLS-1$ MapActivity.launchMapActivityMoveToTop(getActivity()); } private static class Place { public double lat; public double lon; public String displayName; } class PlacesAdapter extends ArrayAdapter<Place> { private LatLon location; public void updateLocation(LatLon l) { location = l; notifyDataSetChanged(); } public PlacesAdapter(List<Place> places) { super(getActivity(), R.layout.search_address_online_list_item, places); } public void setPlaces(List<Place> places) { setNotifyOnChange(false); clear(); for(Place p : places) { add(p); } setNotifyOnChange(true); notifyDataSetChanged(); } @Override public View getView(int position, View convertView, ViewGroup parent) { View row = convertView; if (row == null) { LayoutInflater inflater = getActivity().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(OsmAndFormatter.getFormattedDistance(dist, (OsmandApplication) getActivity().getApplication())); } else { distanceLabel.setText(""); //$NON-NLS-1$ } label.setText(model.displayName); return row; } } }