package ru.shutoff.cgstarter; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.location.Location; import android.net.Uri; import android.os.Bundle; import android.os.CountDownTimer; import android.speech.RecognizerIntent; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonArray; import com.eclipsesource.json.JsonObject; import com.eclipsesource.json.ParseException; import org.apache.commons.lang3.StringUtils; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Locale; import java.util.Vector; public class SearchActivity extends GpsActivity { PlaceholderFragment fragment; static boolean isVoiceSearch(Context context) { PackageManager pm = context.getPackageManager(); List<ResolveInfo> activities = pm.queryIntentActivities(new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0); return activities.size() > 0; } @Override protected void onCreate(Bundle savedInstanceState) { supportRequestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState == null) { fragment = new PlaceholderFragment(); fragment.location = getLastBestLocation(); getSupportFragmentManager().beginTransaction() .add(R.id.container, fragment) .commit(); } setResult(RESULT_CANCELED); } @Override public void locationChanged() { if (fragment != null) { fragment.location = getLastBestLocation(); if (fragment.location != null) fragment.startSearch(); } } public static class PlaceholderFragment extends Fragment { Vector<Address> addr_list; Vector<Phrase> phrases; int phrase; ListView results; View progress; int prev_size; Location location; boolean started; @Override public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.list, container, false); progress = rootView.findViewById(R.id.progress); progress.setVisibility(View.GONE); results = (ListView) rootView.findViewById(R.id.list); results.setVisibility(View.GONE); phrases = new Vector<Phrase>(); addr_list = new Vector<Address>(); if (location != null) startSearch(); CountDownTimer timer = new CountDownTimer(2000, 2000) { @Override public void onTick(long millisUntilFinished) { } @Override public void onFinish() { startSearch(); } }; timer.start(); return rootView; } void startSearch() { if (started) return; started = true; progress.setVisibility(View.VISIBLE); Intent data = getActivity().getIntent(); ArrayList<String> res = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS); float[] scopes = data.getFloatArrayExtra(RecognizerIntent.EXTRA_CONFIDENCE_SCORES); if (scopes == null) scopes = new float[0]; phrases = new Vector<Phrase>(); Bookmarks.Point[] points = Bookmarks.get(getActivity()); for (int i = 0; i < res.size(); i++) { String r = res.get(i); float scope = (i < scopes.length) ? scopes[i] : 0.01f; for (Bookmarks.Point p : points) { float ratio = compare(p.name, r) * 10; if (ratio > 4) { int n = 0; for (n = 0; n < addr_list.size(); n++) { Address addr = addr_list.get(n); if ((addr.lat == p.lat) && (addr.lon == p.lng)) { addr.scope += scope * ratio; break; } } if (n >= addr_list.size()) { Address address = new Address(); address.name = p.name; address.address = ""; address.lat = p.lat; address.lon = p.lng; address.scope = scope * ratio; addr_list.add(address); } } } if (scope == 0) continue; Phrase phrase = new Phrase(); phrase.phrase = r; phrase.scope = scope; phrases.add(phrase); } updateResults(); phrase = 0; if (phrases.size() == 0) { if (getActivity() != null) getActivity().finish(); return; } new Request(); } void updateResults() { if (prev_size == addr_list.size()) return; prev_size = addr_list.size(); if (addr_list.size() == 0) return; if (location != null) { for (Address addr : addr_list) { if (addr.distance != 0) continue; addr.distance = OnExitService.calc_distance(location.getLatitude(), location.getLongitude(), addr.lat, addr.lon); addr.scope /= Math.log(200 + addr.distance); } Collections.sort(addr_list, new Comparator<Address>() { @Override public int compare(Address lhs, Address rhs) { if (lhs.scope < rhs.scope) return 1; if (lhs.scope > rhs.scope) return -1; return 0; } }); } if (results.getVisibility() == View.VISIBLE) { BaseAdapter adapter = (BaseAdapter) results.getAdapter(); adapter.notifyDataSetChanged(); return; } results.setAdapter(new BaseAdapter() { @Override public int getCount() { return addr_list.size(); } @Override public Object getItem(int position) { return addr_list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; if (v == null) { LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(LAYOUT_INFLATER_SERVICE); v = inflater.inflate(R.layout.addr_item, null); } Address addr = addr_list.get(position); TextView tv = (TextView) v.findViewById(R.id.addr); tv.setText(addr.address); tv = (TextView) v.findViewById(R.id.name); tv.setText(addr.name); tv = (TextView) v.findViewById(R.id.dist); if (addr.distance < 100) { tv.setText(""); } else { DecimalFormat df = new DecimalFormat("#.#"); tv.setText(df.format(addr.distance / 1000) + getString(R.string.km)); } return v; } }); progress.setVisibility(View.GONE); results.setVisibility(View.VISIBLE); results.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { Address addr = addr_list.get(i); if (OnExitService.isRunCG(getActivity())) CarMonitor.killCG(getActivity()); CarMonitor.startCG(getActivity(), addr.lat + "|" + addr.lon, null, addr); getActivity().setResult(RESULT_OK); getActivity().finish(); } }); } float compare(String s1, String s2) { String[] w1 = s1.toUpperCase().split(" "); String[] w2 = s2.toUpperCase().split(" "); float res = 0; for (String w : w1) { if (w.equals("")) continue; for (String s : w2) { if (s.equals("")) continue; int lfd = StringUtils.getLevenshteinDistance(w, s); float ratio = ((float) lfd) / Math.min(s.length(), w.length()); if (ratio < 0.5) res += 1 - ratio * 2; } } return res / Math.max(w1.length, w2.length); } class Request extends LocationRequest { Request() { Phrase p = phrases.get(phrase); exec(p.phrase); } @Override Location getLocation() { return location; } @Override void showError(String error) { } @Override void result(Vector<Address> result) { if (result.size() > 0) { float scope = phrases.get(phrase).scope; for (Address addr : result) { addr.scope = scope; addr_list.add(addr); } updateResults(); } if (++phrase >= phrases.size()) { int near_count = 0; Location location = getLocation(); if (location != null) { for (Address addr : addr_list) { if (addr.distance == 0) addr.distance = OnExitService.calc_distance(addr.lat, addr.lon, location.getLatitude(), location.getLongitude()); if (addr.distance < 10000) near_count++; } } else { near_count = addr_list.size(); } if (near_count == 0) { phrase = 0; new NearRequest(); return; } BaseAdapter adapter = (BaseAdapter) results.getAdapter(); adapter.notifyDataSetChanged(); return; } new Request(); } } class NearRequest extends PlaceRequest { NearRequest() { Phrase p = phrases.get(phrase); exec(p.phrase, 1000); } @Override Location getLocation() { return location; } @Override void showError(String error) { } @Override void result(Vector<Address> result) { if (result.size() > 0) { float scope = phrases.get(phrase).scope; for (Address addr : result) { addr.scope = scope; addr_list.add(addr); } updateResults(); } if (++phrase >= phrases.size()) { int near_count = 0; Location location = getLocation(); if (location != null) { for (Address addr : addr_list) { if (addr.distance == 0) addr.distance = OnExitService.calc_distance(addr.lat, addr.lon, location.getLatitude(), location.getLongitude()); if (addr.distance < 10000) near_count++; } } else { near_count = addr_list.size(); } if (near_count == 0) { phrase = 0; new LongRequest(); return; } BaseAdapter adapter = (BaseAdapter) results.getAdapter(); adapter.notifyDataSetChanged(); return; } new NearRequest(); } } class LongRequest extends PlaceRequest { LongRequest() { Phrase p = phrases.get(phrase); exec(p.phrase, 50000); } @Override Location getLocation() { return location; } @Override void showError(String error) { } @Override void result(Vector<Address> result) { if (result.size() > 0) { float scope = phrases.get(phrase).scope; for (Address addr : result) { addr.scope = scope; addr_list.add(addr); } updateResults(); } if (++phrase >= phrases.size()) { if (addr_list.size() == 0) { getActivity().finish(); return; } BaseAdapter adapter = (BaseAdapter) results.getAdapter(); adapter.notifyDataSetChanged(); return; } new LongRequest(); } } } static class Phrase { String phrase; float scope; } static class Address { String address; String name; double lat; double lon; double distance; float scope; } static abstract class PlaceRequest extends HttpTask { String error; abstract Location getLocation(); abstract void showError(String error); abstract void result(Vector<Address> result); void exec(String addr, int radius) { String url = "https://maps.googleapis.com/maps/api/place/textsearch/json?query=%1&sensor=true"; Location location = getLocation(); if (location != null) { double lat = location.getLatitude(); double lon = location.getLongitude(); url += "&location=" + lat + "," + lon + "&radius=" + radius; } url += "&key=AIzaSyBljQKazFWpl9nyGHp-lu8ati7QjMbwzsU"; url += "&language=" + Locale.getDefault().getLanguage(); execute(url, addr); } void result(String result) { JsonArray res = Json.parse(result).asObject().get("results").asArray(); Vector<Address> r = new Vector<Address>(); for (int i = 0; i < res.size(); i++) { JsonObject o = res.get(i).asObject(); Address addr = new Address(); addr.address = o.get("formatted_address").asString(); try { addr.name = o.get("name").asString(); } catch (Exception ex) { // ignore } JsonObject geo = o.get("geometry").asObject().get("location").asObject(); addr.lat = geo.get("lat").asDouble(); addr.lon = geo.get("lng").asDouble(); r.add(addr); } result(r); } void error(String error) { showError(error); } } static public abstract class LocationRequest extends PlaceRequest { void exec(String addr) { String url = "http://maps.googleapis.com/maps/api/geocode/json?address=$1&sensor=true"; Location location = getLocation(); if (location != null) { double lat = location.getLatitude(); double lon = location.getLongitude(); url += "&bounds=" + (lat - 1.5) + "," + (lon - 1.5) + Uri.encode("|") + (lat + 1.5) + "," + (lon + 1.5); } url += "&language=" + Locale.getDefault().getLanguage(); execute(url, addr); } void result(String data) throws ParseException { JsonArray res = Json.parse(data).asObject().get("results").asArray(); Vector<Address> r = new Vector<Address>(); for (int i = 0; i < res.size(); i++) { JsonObject o = res.get(i).asObject(); Address addr = new Address(); addr.address = o.get("formatted_address").asString(); JsonObject geo = o.get("geometry").asObject().get("location").asObject(); addr.lat = geo.get("lat").asDouble(); addr.lon = geo.get("lng").asDouble(); r.add(addr); } result(r); } } }