// Created by plusminus on 18:17:25 - 12.12.2008 package org.androad.ui.sd; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.osmdroid.util.GeoPoint; import org.androad.R; import org.androad.db.DBManager; import org.androad.db.DataBaseException; import org.androad.exc.Exceptor; import org.androad.preferences.Preferences; import org.androad.sys.ors.adt.GeocodedAddress; import org.androad.sys.ors.adt.lus.Country; import org.androad.sys.ors.adt.lus.ICountrySubdivision; import org.androad.sys.ors.exceptions.ORSException; import org.androad.sys.ors.lus.LUSRequester; import org.androad.ui.AndNavBaseActivity; import org.androad.ui.common.OnClickOnFocusChangedListenerAdapter; import org.androad.ui.map.OpenStreetDDMap; import org.androad.ui.sd.util.StreetInfoExtractor; import org.androad.util.UserTask; import org.androad.util.constants.Constants; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.DialogInterface.OnCancelListener; import android.media.MediaPlayer; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import android.widget.AdapterView.OnItemClickListener; public class SDResolver extends AndNavBaseActivity { // =========================================================== // Constants // =========================================================== private static final int REQUESTCODE_DDMAP = 0x1337; private static final String STATE_RESOLVEDADDRESSES_ITEMS_ID = "state_resolvedaddresses_items_id"; // =========================================================== // Fields // =========================================================== private Bundle mBundleCreatedWith; private ListView mResolvedAddressesList; private ArrayList<GeocodedAddressItem> mResolvedItems = new ArrayList<GeocodedAddressItem>(); private boolean mResolvingFinished = false; // =========================================================== // Constructors // =========================================================== /** Called when the activity is first created. */ @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState, true); // We need DataState-Info ... do we ? Preferences.applySharedSettings(this); this.setContentView(R.layout.sd_resolver); this.mBundleCreatedWith = this.getIntent().getExtras(); this.mResolvedAddressesList = (ListView)this.findViewById(R.id.list_resolvedaddresses); /* Set empty view for the list. */ final TextView empty = new TextView(this); empty.setText(R.string.list_empty); this.mResolvedAddressesList.setEmptyView(empty); applyTopMenuButtonListeners(); initListView(); if(savedInstanceState == null) { resolveAddressToListItemsAsync(); } } // =========================================================== // Getter & Setter // =========================================================== // =========================================================== // Methods from SuperClass/Interfaces // =========================================================== @Override public void onSaveInstanceState(final Bundle out) { if(this.mResolvingFinished) { out.putParcelableArrayList(STATE_RESOLVEDADDRESSES_ITEMS_ID, this.mResolvedItems); } } @Override protected void onRestoreInstanceState(final Bundle in) { final ArrayList<GeocodedAddressItem> restoredItems = in.getParcelableArrayList(STATE_RESOLVEDADDRESSES_ITEMS_ID); if(restoredItems == null){ resolveAddressToListItemsAsync(); }else{ this.mResolvedItems = restoredItems; final GeocodedAddressesListAdapter gla = new GeocodedAddressesListAdapter(this); gla.setListItems(this.mResolvedItems); this.mResolvedAddressesList.setAdapter(gla); this.mResolvingFinished = true; } } @Override protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { switch(resultCode){ case SUBACTIVITY_RESULTCODE_CHAINCLOSE_SUCCESS: this.setResult(SUBACTIVITY_RESULTCODE_CHAINCLOSE_SUCCESS, data); this.finish(); break; case SUBACTIVITY_RESULTCODE_CHAINCLOSE_QUITTED: this.setResult(SUBACTIVITY_RESULTCODE_CHAINCLOSE_QUITTED, data); this.finish(); break; } /* Finally call the super()-method. */ super.onActivityResult(requestCode, resultCode, data); } // =========================================================== // Methods // =========================================================== protected void applyTopMenuButtonListeners() { /* Set Listener for Back-Button. */ new OnClickOnFocusChangedListenerAdapter(this.findViewById(R.id.ibtn_sd_resolver_back)) { @Override public void onClicked(final View me) { if (SDResolver.super.mMenuVoiceEnabled) { MediaPlayer.create(SDResolver.this, R.raw.close).start(); } /* Back one level. */ SDResolver.this.setResult(SUBACTIVITY_RESULTCODE_UP_ONE_LEVEL); SDResolver.this.finish(); } }; /* Set Listener for Close-Button. */ new OnClickOnFocusChangedListenerAdapter(this.findViewById(R.id.ibtn_sd_resolver_close)) { @Override public void onClicked(final View me) { if (SDResolver.super.mMenuVoiceEnabled) { MediaPlayer.create(SDResolver.this, R.raw.close).start(); } /* * Set ResultCode that the calling activity knows that we want * to go back to the Base-Menu */ SDResolver.this.setResult(SUBACTIVITY_RESULTCODE_CHAINCLOSE_QUITTED); SDResolver.this.finish(); } }; } private void resolveAddressToListItemsAsync() { final GeocodedAddressesListAdapter gala = new GeocodedAddressesListAdapter(SDResolver.this); final UserTask<Void, Integer, Void> ut; final ProgressDialog pd = ProgressDialog.show(this, getString(R.string.dlg_sd_resolver_loading_title), getString(R.string.please_wait_a_moment), true, true); ut = new UserTask<Void, Integer, Void>(){ @Override public Void doInBackground(final Void... params) { try{ ArrayList<GeocodedAddress> resolved = null; final Bundle extras = SDResolver.this.mBundleCreatedWith; // Drag to local field final Country nat = extras.getParcelable(EXTRAS_COUNTRY_ID); final ICountrySubdivision subdivision = extras.getParcelable(EXTRAS_COUNTRYSUBDIVISIONCODE_ID); final String streetName = extras.getString(EXTRAS_STREET_ID); final String streetNumber = extras.getString(EXTRAS_STREETNUMBER_ID); /* Switch on the Mode. */ final int searchMode = extras.getInt(EXTRAS_MODE); final LUSRequester lus = Preferences.getORSServer(SDResolver.this).LOCATIONUTILITYSERVICE; switch (searchMode) { case EXTRAS_MODE_STREETNAMESEARCH: final String dummycityname = ""; resolved = lus.requestStreetaddressCity(SDResolver.this, nat, subdivision, dummycityname, streetName, streetNumber); break; case EXTRAS_MODE_FREEFORMSEARCH: final String freeformAddress = extras.getString(EXTRAS_FREEFORM_ID); resolved = lus.requestFreeformAddress(SDResolver.this, nat, freeformAddress); break; case EXTRAS_MODE_ZIPSEARCH: final String zipCode = extras.getString(EXTRAS_ZIPCODE_ID); resolved = lus.requestStreetaddressPostalcode(SDResolver.this, nat, subdivision, zipCode, streetName, streetNumber); break; case EXTRAS_MODE_CITYNAMESEARCH: final String cityname = extras.getString(EXTRAS_CITYNAME_ID); resolved = lus.requestStreetaddressCity(SDResolver.this, nat, subdivision, cityname, streetName, streetNumber); break; default: throw new IllegalArgumentException("Unawaited MODE in SDResolver."); } if(resolved == null || resolved.size() == 0){ runOnUiThread(new Runnable(){ @Override public void run() { Toast.makeText(SDResolver.this, R.string.toast_could_not_resolve_address, Toast.LENGTH_LONG).show(); } }); }else{ for(final GeocodedAddress ga : resolved) { SDResolver.this.mResolvedItems.add(new GeocodedAddressItem(ga)); } } /* Adapt the list to the Adapter. */ gala.setListItems(SDResolver.this.mResolvedItems);/* Orders by name, ascending. */ SDResolver.this.mResolvingFinished = true; }catch(final ORSException e){ runOnUiThread(new Runnable(){ @Override public void run() { Toast.makeText(SDResolver.this, R.string.toast_could_not_resolve_address, Toast.LENGTH_LONG).show(); } }); }catch(final Exception e){ Exceptor.e("SDResolver-Exception", e, SDResolver.this); } return null; } @Override public void onPostExecute(final Void result) { /* Adapt the Adapter to the ListView. */ SDResolver.this.mResolvedAddressesList.setAdapter(gala); try{ pd.dismiss(); }catch(final IllegalArgumentException ia){ // Nothing } } }; pd.setOnCancelListener(new OnCancelListener(){ @Override public void onCancel(final DialogInterface d) { d.dismiss(); if(ut != null) { ut.cancel(true); } } }); ut.execute(); } protected void initListView() { this.mResolvedAddressesList.setOnItemClickListener(new OnItemClickListener(){ @Override public void onItemClick(final AdapterView<?> parent, final View v, final int position, final long id) { final GeocodedAddressItem r = (GeocodedAddressItem)parent.getAdapter().getItem(position); final int searchMode = SDResolver.this.mBundleCreatedWith.getInt(EXTRAS_MODE); final String name = getFavoriteEntry(); if(searchMode == EXTRAS_MODE_ZIPSEARCH || searchMode == EXTRAS_MODE_CITYNAMESEARCH){ final GeoPoint dest = r.mGeocodedAddress; try { DBManager.addFavorite(SDResolver.this, name, dest.getLatitudeE6(), dest.getLongitudeE6()); } catch (final DataBaseException e) { Log.e(Constants.DEBUGTAG, "Error adding Favorite", e); } } /* Proceed to next screen. */ final int mode = SDResolver.this.mBundleCreatedWith.getInt(MODE_SD); final Bundle b = new Bundle(); b.putInt(EXTRAS_MODE, EXTRAS_MODE_DIRECT_LATLNG); b.putString(EXTRAS_COUNTRY_ID, SDResolver.this.mBundleCreatedWith.getString(EXTRAS_COUNTRY_ID)); // Adds the country if available b.putInt(EXTRAS_DESTINATION_LATITUDE_ID, r.mGeocodedAddress.getLatitudeE6()); b.putInt(EXTRAS_DESTINATION_LONGITUDE_ID, r.mGeocodedAddress.getLongitudeE6()); b.putString(EXTRAS_DESTINATION_TITLE, name); switch(mode){ case MODE_SD_DESTINATION: final Intent directIntent = new Intent(SDResolver.this, OpenStreetDDMap.class); directIntent.putExtras(b); SDResolver.this.startActivityForResult(directIntent, REQUESTCODE_DDMAP); break; case MODE_SD_RESOLVE: case MODE_SD_WAYPOINT: final Intent resultData = new Intent(); resultData.putExtras(b); SDResolver.this.setResult(SUBACTIVITY_RESULTCODE_CHAINCLOSE_SUCCESS, resultData); SDResolver.this.finish(); } } }); } private String getFavoriteEntry() { final StringBuilder sb = new StringBuilder(); /* Switch on the Mode. */ final Bundle extras = this.mBundleCreatedWith; // Drag to local field final Country nat = extras.getParcelable(EXTRAS_COUNTRY_ID); final String streetName = extras.getString(EXTRAS_STREET_ID); final String streetNumber = extras.getString(EXTRAS_STREETNUMBER_ID); final int searchMode = extras.getInt(EXTRAS_MODE); switch (searchMode) { case EXTRAS_MODE_STREETNAMESEARCH: sb.append(getString(nat.NAMERESID)); sb.append(' '); sb.append(StreetInfoExtractor.constructStreetLineInfo(this, streetName, streetNumber, nat)); break; case EXTRAS_MODE_FREEFORMSEARCH: sb.append(extras.getString(EXTRAS_FREEFORM_ID)); break; case EXTRAS_MODE_ZIPSEARCH: case EXTRAS_MODE_CITYNAMESEARCH: sb.append(getString(nat.NAMERESID)); sb.append(' '); final String zipCodeOrCityName = org.androad.ui.sd.Util.getZipCodeOrCityName(this.mBundleCreatedWith); sb.append(zipCodeOrCityName); sb.append(' '); sb.append(StreetInfoExtractor.constructStreetLineInfo(this, streetName, streetNumber, nat)); break; } return sb.toString(); } // =========================================================== // Inner and Anonymous Classes // =========================================================== private static class GeocodedAddressItem implements Comparable<GeocodedAddressItem>, Parcelable { protected final GeocodedAddress mGeocodedAddress; private GeocodedAddressItem(final GeocodedAddress pGeocodedAddress) { this.mGeocodedAddress = pGeocodedAddress; } @Override public int compareTo(final GeocodedAddressItem another) { final float diff = -(this.mGeocodedAddress.getAccuracy() - another.mGeocodedAddress.getAccuracy()); if(Math.abs(diff) < 0.001f){ final int cityDiff = this.mGeocodedAddress.getMunicipality().compareToIgnoreCase(another.mGeocodedAddress.getMunicipality()); if(cityDiff != 0 || this.mGeocodedAddress.getStreetNameOfficial() == null){ return cityDiff; }else{ return this.mGeocodedAddress.getStreetNameOfficial().compareToIgnoreCase(another.mGeocodedAddress.getStreetNameOfficial()); } }else if(diff < 0){ return -1; // this before another }else{ return 1; } } // =========================================================== // Parcelable // =========================================================== public static final Parcelable.Creator<GeocodedAddressItem> CREATOR = new Parcelable.Creator<GeocodedAddressItem>() { public GeocodedAddressItem createFromParcel(final Parcel in) { return readFromParcel(in); } public GeocodedAddressItem[] newArray(final int size) { return new GeocodedAddressItem[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(final Parcel out, final int flags) { out.writeParcelable(this.mGeocodedAddress, 0); } private static GeocodedAddressItem readFromParcel(final Parcel in){ final GeocodedAddress addr = in.readParcelable(GeocodedAddress.class.getClassLoader()); return new GeocodedAddressItem(addr); } } private class GeoCodedAddressListItemView extends LinearLayout{ private final ImageView mIVNationality; private final TextView mTVMunicipality; private final TextView mTVStreet; public GeoCodedAddressListItemView(final Context context, final GeocodedAddressItem aItem) { super(context); this.setOrientation(HORIZONTAL); final GeocodedAddress ga = aItem.mGeocodedAddress; final Country nat = ga.getNationality(); this.mIVNationality = new ImageView(context); this.mIVNationality.setPadding(10, 0, 10, 0); this.mIVNationality.setImageResource(nat.FLAGRESID); addView(this.mIVNationality); final LinearLayout ll = new LinearLayout(context); ll.setLayoutParams(new LinearLayout.LayoutParams(android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT)); ll.setOrientation(VERTICAL); addView(ll); /* CityLine */ final String cityLine = StreetInfoExtractor.constructCityLineInfo(context, ga.getMunicipality(), ga.getPostalCode(), nat); this.mTVMunicipality = new TextView(context); this.mTVMunicipality.setText(cityLine); this.mTVMunicipality.setTextSize(TypedValue.COMPLEX_UNIT_PX, 26); this.mTVMunicipality.setPadding(10,0,10,0); ll.addView(this.mTVMunicipality, new LinearLayout.LayoutParams(android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT)); /* StreetLine */ this.mTVStreet = new TextView(context); final String streetName = ga.getStreetNameOfficial(); final String streetNumber = ga.getStreetNumber(); final String streetLine = StreetInfoExtractor.constructStreetLineInfo(context, streetName, streetNumber, nat); if(streetLine != null && streetLine.length() > 0) { this.mTVStreet.setText(streetLine); this.mTVStreet.setTextSize(TypedValue.COMPLEX_UNIT_PX, 18); ll.addView(this.mTVStreet, new LinearLayout.LayoutParams(android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT)); } } } private class GeocodedAddressesListAdapter extends BaseAdapter { /** Remember our context so we can use it when constructing views. */ private final Context mContext; private List<GeocodedAddressItem> mItems = new ArrayList<GeocodedAddressItem>(); public GeocodedAddressesListAdapter(final Context context) { this.mContext = context; } public void addItem(final GeocodedAddressItem it) { this.mItems.add(it); Collections.sort(this.mItems); } public void setListItems(final List<GeocodedAddressItem> lit) { this.mItems = lit; Collections.sort(this.mItems); } @Override public boolean isEmpty() { return this.mItems == null || this.mItems.size() == 0; } /** @return The number of items in the */ public int getCount() { return this.mItems.size(); } public Object getItem(final int position) { return this.mItems.get(position); } @Override public long getItemId(final int position) { return position; } @Override public View getView(final int position, final View convertView, final ViewGroup parent) { GeoCodedAddressListItemView btv; if (convertView == null) { btv = new GeoCodedAddressListItemView(this.mContext, this.mItems.get(position)); } else { // Reuse/Overwrite the View passed // We are assuming(!) that it is castable! btv = (GeoCodedAddressListItemView) convertView; final GeocodedAddress ga = this.mItems.get(position).mGeocodedAddress; final Country nat = ga.getNationality(); btv.mIVNationality.setImageResource(nat.FLAGRESID); btv.mTVMunicipality.setText(StreetInfoExtractor.constructCityLineInfo(this.mContext, ga.getMunicipality(), ga.getPostalCode(), nat)); final String streetLine = StreetInfoExtractor.constructStreetLineInfo(this.mContext, ga.getStreetNameOfficial(), ga.getStreetNumber(), nat); if(streetLine != null && streetLine.length() > 0) { btv.mTVStreet.setText(streetLine); } } return btv; } } }