package me.guillaumin.android.osmtracker.activity; import java.sql.Date; import java.text.DateFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import me.guillaumin.android.osmtracker.OSMTracker; import me.guillaumin.android.osmtracker.R; import me.guillaumin.android.osmtracker.db.TrackContentProvider; import me.guillaumin.android.osmtracker.db.TrackContentProvider.Schema; import me.guillaumin.android.osmtracker.db.model.Track; import me.guillaumin.android.osmtracker.gpx.ExportToStorageTask; import me.guillaumin.android.osmtracker.util.MercatorProjection; import android.content.ContentResolver; import android.content.ContentUris; import android.content.Intent; import android.database.Cursor; import android.graphics.Paint; import android.os.Bundle; import android.preference.PreferenceManager; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.Button; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; import android.widget.Toast; /** * Display details about one track. Allow naming the track. * The track ID is passed into the Bundle via {@link Schema#COL_TRACK_ID}. * * @author Jeremy D Monin <jdmonin@nand.net> * */ public class TrackDetail extends TrackDetailEditor implements AdapterView.OnItemClickListener { @SuppressWarnings("unused") private static final String TAG = TrackDetail.class.getSimpleName(); /** * Key to bind the "key" of each item using SimpleListAdapter */ private static final String ITEM_KEY = "key"; /** * Key to bind the "value" of each item using SimpleListAdapter */ private static final String ITEM_VALUE = "value"; /** * Position of the waypoints counts in the list */ private static final int WP_COUNT_INDEX = 0; /** Does this track have any waypoints? If true, underline Waypoint count in the list. */ private boolean trackHasWaypoints = false; /** * List with track info */ private ListView lv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState, R.layout.trackdetail, getIntent().getExtras().getLong(Schema.COL_TRACK_ID)); lv = (ListView) findViewById(R.id.trackdetail_list); final Button btnOk = (Button) findViewById(R.id.trackdetail_btn_ok); btnOk.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { save(); finish(); } }); final Button btnCancel = (Button) findViewById(R.id.trackdetail_btn_cancel); btnCancel.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // Just close the dialog finish(); } }); // Do not show soft keyboard by default getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); // further work is done in onResume. } @Override protected void onResume() { super.onResume(); // Query the track values ContentResolver cr = getContentResolver(); Cursor cursor = cr.query( ContentUris.withAppendedId(TrackContentProvider.CONTENT_URI_TRACK, trackId), null, null, null, null); if (! cursor.moveToFirst()) { // This shouldn't occur, it's here just in case. // So, don't make each language translate/localize it. Toast.makeText(this, "Track ID not found.", Toast.LENGTH_SHORT).show(); cursor.close(); finish(); return; // <--- Early return --- } // Bind WP count, TP count, start date, etc. // Fill name-field only if empty (in case changed by user/restored by onRestoreInstanceState) Track t = Track.build(trackId, cursor, cr, true); bindTrack(t); String from[] = new String[]{ITEM_KEY, ITEM_VALUE}; int[] to = new int[] {R.id.trackdetail_item_key, R.id.trackdetail_item_value}; // Waypoint count final int wpCount = t.getWpCount(); trackHasWaypoints = (wpCount > 0); List<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>(); HashMap<String, String> map = new HashMap<String, String>(); map.put(ITEM_KEY, getResources().getString(R.string.trackmgr_waypoints_count)); map.put(ITEM_VALUE, Integer.toString(wpCount)); data.add(WP_COUNT_INDEX, map); // Trackpoint count map = new HashMap<String, String>(); map.put(ITEM_KEY, getResources().getString(R.string.trackmgr_trackpoints_count)); map.put(ITEM_VALUE, Integer.toString(t.getTpCount())); data.add(map); // Start date map = new HashMap<String, String>(); map.put(ITEM_KEY, getResources().getString(R.string.trackdetail_startdate)); map.put(ITEM_VALUE, t.getStartDateAsString()); data.add(map); // End date map = new HashMap<String, String>(); map.put(ITEM_KEY, getResources().getString(R.string.trackdetail_enddate)); map.put(ITEM_VALUE, t.getEndDateAsString()); data.add(map); // Start point map = new HashMap<String, String>(); map.put(ITEM_KEY, getResources().getString(R.string.trackdetail_startloc)); map.put(ITEM_VALUE, MercatorProjection.formatDegreesAsDMS(t.getStartLat(), true) + " " + MercatorProjection.formatDegreesAsDMS(t.getStartLong(), false)); data.add(map); // End point map = new HashMap<String, String>(); map.put(ITEM_KEY, getResources().getString(R.string.trackdetail_endloc)); map.put(ITEM_VALUE, MercatorProjection.formatDegreesAsDMS(t.getEndLat(), true) + " " + MercatorProjection.formatDegreesAsDMS(t.getEndLong(), false)); data.add(map); // OSM Upload date map = new HashMap<String, String>(); map.put(ITEM_KEY, getResources().getString(R.string.trackdetail_osm_upload_date)); if (cursor.isNull(cursor.getColumnIndex(Schema.COL_OSM_UPLOAD_DATE))) { map.put(ITEM_VALUE, getResources().getString(R.string.trackdetail_osm_upload_notyet)); } else { map.put(ITEM_VALUE, DateFormat.getDateTimeInstance().format(new Date(cursor.getLong(cursor.getColumnIndex(Schema.COL_EXPORT_DATE))))); } data.add(map); // Exported date. Should be the last item in order to be refreshed // if the user exports the track map = new HashMap<String, String>(); map.put(ITEM_KEY, getResources().getString(R.string.trackdetail_exportdate)); if (cursor.isNull(cursor.getColumnIndex(Schema.COL_EXPORT_DATE))) { map.put(ITEM_VALUE, getResources().getString(R.string.trackdetail_export_notyet)); } else { map.put(ITEM_VALUE, (DateFormat.getDateTimeInstance().format(new Date(cursor.getLong(cursor.getColumnIndex(Schema.COL_EXPORT_DATE)))))); } data.add(map); cursor.close(); TrackDetailSimpleAdapter adapter = new TrackDetailSimpleAdapter(data, from, to); lv.setAdapter(adapter); // Click on Waypoint count to see the track's WaypointList lv.setOnItemClickListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.trackdetail_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { Intent i; switch(item.getItemId()) { case R.id.trackdetail_menu_save: save(); finish(); break; case R.id.trackdetail_menu_cancel: finish(); break; case R.id.trackdetail_menu_display: boolean useOpenStreetMapBackground = PreferenceManager.getDefaultSharedPreferences(this).getBoolean( OSMTracker.Preferences.KEY_UI_DISPLAYTRACK_OSM, OSMTracker.Preferences.VAL_UI_DISPLAYTRACK_OSM); if (useOpenStreetMapBackground) { i = new Intent(this, DisplayTrackMap.class); } else { i = new Intent(this, DisplayTrack.class); } i.putExtra(Schema.COL_TRACK_ID, trackId); startActivity(i); break; case R.id.trackdetail_menu_export: new ExportToStorageTask(this, trackId).execute(); // Pick last list item (Exported date) and update it SimpleAdapter adapter = ((SimpleAdapter) lv.getAdapter()); @SuppressWarnings("unchecked") Map<String, String> data = (Map<String, String>) adapter.getItem(adapter.getCount()-1); data.put(ITEM_VALUE, DateFormat.getDateTimeInstance().format(new Date(System.currentTimeMillis()))); adapter.notifyDataSetChanged(); break; case R.id.trackdetail_menu_osm_upload: i = new Intent(this, OpenStreetMapUpload.class); i.putExtra(Schema.COL_TRACK_ID, trackId); startActivity(i); break; } return super.onOptionsItemSelected(item); } /** * Handle clicks on list items; for Waypoint count, show this track's list of waypoints ({@link WaypointList}). * Ignore all other clicks. * @param position Item number in the list; this method assumes Waypoint count is position 0 (first item). */ public void onItemClick(AdapterView<?> parent, View view, final int position, final long rowid) { if (position != WP_COUNT_INDEX) { return; } Intent i = new Intent(this, WaypointList.class); i.putExtra(Schema.COL_TRACK_ID, trackId); startActivity(i); } /** * Extend SimpleAdapter so we can underline the clickable Waypoint count. * Always uses <tt>R.layout.trackdetail_item</tt> as its list item resource. */ private class TrackDetailSimpleAdapter extends SimpleAdapter { public TrackDetailSimpleAdapter (List<? extends Map<String, ?>> data, String[] from, int[] to) { super(TrackDetail.this, data, R.layout.trackdetail_item, from, to); } /** * Get the layout for this list item. (<tt>trackdetail_item.xml</tt>) * @param position Item number in the list */ public View getView(final int position, View convertView, ViewGroup parent) { View v = super.getView(position, convertView, parent); if (! (v instanceof ViewGroup)) return v; // should not happen; v is trackdetail_item, a LinearLayout final boolean wantsUnderline = ((position == WP_COUNT_INDEX) && trackHasWaypoints); View vi = ((ViewGroup) v).findViewById(R.id.trackdetail_item_key); if ((vi != null) && (vi instanceof TextView)) { final int flags = ((TextView) vi).getPaintFlags(); if (wantsUnderline) ((TextView) vi).setPaintFlags(flags | Paint.UNDERLINE_TEXT_FLAG); else ((TextView) vi).setPaintFlags(flags & ~Paint.UNDERLINE_TEXT_FLAG); } return v; } } // inner class TrackDetailSimpleAdapter } // public class TrackDetail