package com.robert.maps.applib.kml; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.text.SimpleDateFormat; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import android.app.Activity; import android.app.AlertDialog; import android.app.ListActivity; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.preference.PreferenceManager; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.Button; import android.widget.CheckBox; import android.widget.ListView; import android.widget.SimpleCursorAdapter; import android.widget.Toast; import com.robert.maps.applib.R; import com.robert.maps.applib.kml.Track.TrackPoint; import com.robert.maps.applib.kml.XMLparser.SimpleXML; import com.robert.maps.applib.trackwriter.DatabaseHelper; import com.robert.maps.applib.utils.SimpleThreadFactory; import com.robert.maps.applib.utils.Ut; public class TrackListActivity extends ListActivity { private PoiManager mPoiManager; private ProgressDialog dlgWait; private SimpleInvalidationHandler mHandler; private boolean mNeedTracksStatUpdate = false; private ExecutorService mThreadExecutor = null; private int mUnits = 0; private String mSortOrder; private class SimpleInvalidationHandler extends Handler { @Override public void handleMessage(final Message msg) { if(msg.what == R.id.about) { ((SimpleCursorAdapter) getListAdapter()).getCursor().requery(); } else if(msg.what == R.id.tracks) { if(msg.arg1 == 0) Toast.makeText(TrackListActivity.this, R.string.trackwriter_nothing, Toast.LENGTH_LONG).show(); else Toast.makeText(TrackListActivity.this, R.string.trackwriter_saved, Toast.LENGTH_LONG).show(); ((SimpleCursorAdapter) getListAdapter()).getCursor().requery(); } else if(msg.what == R.id.menu_exporttogpxpoi) { if (msg.arg1 == 0) Toast .makeText(TrackListActivity.this, getString(R.string.message_error) + " " + (String) msg.obj, Toast.LENGTH_LONG).show(); else Toast.makeText(TrackListActivity.this, getString(R.string.message_trackexported) + " " + (String) msg.obj, Toast.LENGTH_LONG).show(); } } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(R.layout.track_list); registerForContextMenu(getListView()); mPoiManager = new PoiManager(this); mSortOrder = "trackid DESC"; mHandler = new SimpleInvalidationHandler(); ((Button) findViewById(R.id.startButton)) .setOnClickListener(new OnClickListener() { public void onClick(View v) { startService(new Intent("com.robert.maps.trackwriter")); } }); ((Button) findViewById(R.id.pauseButton)) .setOnClickListener(new OnClickListener() { public void onClick(View v) { stopService(new Intent("com.robert.maps.trackwriter")); } }); ((Button) findViewById(R.id.stopButton)) .setOnClickListener(new OnClickListener() { public void onClick(View v) { stopService(new Intent("com.robert.maps.trackwriter")); doSaveTrack(); } }); ((Button) findViewById(R.id.xavTrackMenuButton)) .setOnClickListener(new OnClickListener() { public void onClick(View v) { (TrackListActivity.this).openOptionsMenu(); } }); SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE); final int versionDataUpdate = settings.getInt("versionDataUpdate", 0); final SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this); mUnits = Integer.parseInt(pref.getString("pref_units", "0")); if(versionDataUpdate < 8){ mNeedTracksStatUpdate = true; SharedPreferences.Editor editor = settings.edit(); editor.putInt("versionDataUpdate", 8); editor.commit(); } } @Override protected void onDestroy() { if(mThreadExecutor != null) mThreadExecutor.shutdown(); super.onDestroy(); mPoiManager.FreeDatabases(); } private void doSaveTrack(){ dlgWait = Ut.ShowWaitDialog(this, 0); if(mThreadExecutor == null) mThreadExecutor = Executors.newSingleThreadExecutor(new SimpleThreadFactory("doSaveTrack")); this.mThreadExecutor.execute(new Runnable() { public void run() { SQLiteDatabase db = null; File folder = Ut.getRMapsMainDir(TrackListActivity.this, "data"); if(folder.canRead()){ try { db = new DatabaseHelper(TrackListActivity.this, folder.getAbsolutePath() + "/writedtrack.db").getWritableDatabase(); } catch (Exception e) { db = null; } }; int res = 0; if(db != null){ try { res = mPoiManager.getGeoDatabase().saveTrackFromWriter(db); } catch (Exception e) { } db.close(); if(res > 0){ Track tr = mPoiManager.getTrack(res); tr.CalculateStat(); mPoiManager.updateTrack(tr); } }; dlgWait.dismiss(); Message.obtain(mHandler, R.id.tracks, res, 0).sendToTarget(); } }); } private void doJoinTracks() { dlgWait = Ut.ShowWaitDialog(this, 0); if(mThreadExecutor == null) mThreadExecutor = Executors.newSingleThreadExecutor(new SimpleThreadFactory("doSaveTrack")); this.mThreadExecutor.execute(new Runnable() { public void run() { int res = -1; try { res = (int)mPoiManager.getGeoDatabase().JoinTracks(); } catch (Exception e) { }; if(res > 0){ Track tr = mPoiManager.getTrack(res); tr.CalculateStat(); mPoiManager.updateTrack(tr); } else { res = 0; // Nothing to save } dlgWait.dismiss(); Message.obtain(mHandler, R.id.tracks, res, 0).sendToTarget(); } }); } @Override protected void onPause() { SharedPreferences uiState = getPreferences(Activity.MODE_PRIVATE); SharedPreferences.Editor editor = uiState.edit(); editor.putString("sortOrder", mSortOrder); editor.commit(); super.onPause(); } @Override protected void onResume() { final SharedPreferences uiState = getPreferences(Activity.MODE_PRIVATE); mSortOrder = uiState.getString("sortOrder", mSortOrder); FillData(); super.onResume(); } private void FillData() { Cursor c = mPoiManager.getGeoDatabase().getTrackListCursor(mUnits == 0 ? getResources().getString(R.string.km) : getResources().getString(R.string.ml), mSortOrder); if(mNeedTracksStatUpdate){ mNeedTracksStatUpdate = false; if(c != null){ if(c.moveToFirst()){ if(c.getInt(8) == -1){ UpdateTracksStat(); } } } } if(c != null){ startManagingCursor(c); SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.tracklist_item , c, new String[] { "name", "title2", "show", "cnt", "distance" + mUnits, "duration", "units"/*, "descr"*/ }, new int[] { R.id.title1, R.id.title2, R.id.checkbox, R.id.data_value1, R.id.data_value2, R.id.data_value3, R.id.data_unit2 /*, R.id.descr*/ }); adapter.setViewBinder(mViewBinder); setListAdapter(adapter); }; } private SimpleCursorAdapter.ViewBinder mViewBinder = new CheckBoxViewBinder(); private class CheckBoxViewBinder implements SimpleCursorAdapter.ViewBinder { private static final String SHOW = "show"; public boolean setViewValue(View view, Cursor cursor, int columnIndex) { if(cursor.getColumnName(columnIndex).equalsIgnoreCase(SHOW)) { ((CheckBox)view.findViewById(R.id.checkbox)).setChecked(cursor.getInt(columnIndex) == 1); return true; } return false; } } private void UpdateTracksStat() { if(mThreadExecutor == null) mThreadExecutor = Executors.newSingleThreadExecutor(new SimpleThreadFactory("UpdateTracksStat")); dlgWait = Ut.ShowWaitDialog(this, 0); mThreadExecutor.execute(new Runnable(){ public void run() { Cursor c = mPoiManager.getGeoDatabase().getTrackListCursor(""); if(c != null){ if (c.moveToFirst()) { Track tr = null; do { tr = mPoiManager.getTrack(c.getInt(3)); if(tr != null){ tr.Category = 0; tr.Activity = 0; final List<Track.TrackPoint> tps = tr.getPoints(); if(tps.size() > 0){ tr.Date = tps.get(0).date; } tr.CalculateStat(); mPoiManager.updateTrack(tr); } } while (c.moveToNext()); } c.close(); } TrackListActivity.this.dlgWait.dismiss(); Message.obtain(mHandler, R.id.about, 0, 0).sendToTarget(); }}); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.tracklist, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item); if(item.getItemId() == R.id.menu_importpoi) { startActivity((new Intent(this, ImportTrackActivity.class))); return true; } else if(item.getItemId() == R.id.menu_sort_name) { if(mSortOrder.contains("tracks.name")) { if(mSortOrder.contains("asc")) mSortOrder = "tracks.name desc"; else mSortOrder = "tracks.name asc"; } else { mSortOrder = "tracks.name asc"; } ((SimpleCursorAdapter) getListAdapter()).changeCursor(mPoiManager.getGeoDatabase().getTrackListCursor(mUnits == 0 ? getResources().getString(R.string.km) : getResources().getString(R.string.ml), mSortOrder)); } else if(item.getItemId() == R.id.menu_sort_category) { if(mSortOrder.contains("activity.name")) { if(mSortOrder.contains("asc")) mSortOrder = "activity.name desc"; else mSortOrder = "activity.name asc"; } else { mSortOrder = "activity.name asc"; } ((SimpleCursorAdapter) getListAdapter()).changeCursor(mPoiManager.getGeoDatabase().getTrackListCursor(mUnits == 0 ? getResources().getString(R.string.km) : getResources().getString(R.string.ml), mSortOrder)); } else if(item.getItemId() == R.id.menu_sort_date) { if(mSortOrder.contains("date")) { if(mSortOrder.contains("asc")) mSortOrder = "date desc"; else mSortOrder = "date asc"; } else { mSortOrder = "date asc"; } ((SimpleCursorAdapter) getListAdapter()).changeCursor(mPoiManager.getGeoDatabase().getTrackListCursor(mUnits == 0 ? getResources().getString(R.string.km) : getResources().getString(R.string.ml), mSortOrder)); } else if(item.getItemId() == R.id.menu_join) { doJoinTracks(); } return true; } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { menu.add(0, R.id.menu_gotopoi, 0, getText(R.string.menu_goto_track)); menu.add(0, R.id.menu_stat, 0, getText(R.string.menu_stat)); menu.add(0, R.id.menu_editpoi, 0, getText(R.string.menu_edit)); menu.add(0, R.id.menu_deletepoi, 0, getText(R.string.menu_delete)); menu.add(0, R.id.menu_exporttogpxpoi, 0, getText(R.string.menu_exporttogpx)); menu.add(0, R.id.menu_exporttokmlpoi, 0, getText(R.string.menu_exporttokml)); super.onCreateContextMenu(menu, v, menuInfo); } @Override public boolean onContextItemSelected(MenuItem item) { final int id = (int) ((AdapterView.AdapterContextMenuInfo)item.getMenuInfo()).id; if(item.getItemId() == R.id.menu_stat) { startActivity((new Intent(this, TrackStatActivity.class)).putExtra("id", id)); } else if(item.getItemId() == R.id.menu_editpoi) { startActivity((new Intent(this, TrackActivity.class)).putExtra("id", id)); } else if(item.getItemId() == R.id.menu_gotopoi) { setResult(RESULT_OK, (new Intent()).putExtra("trackid", id)); finish(); } else if(item.getItemId() == R.id.menu_deletepoi) { new AlertDialog.Builder(this) .setTitle(R.string.app_name) .setMessage(getResources().getString(R.string.question_delete, getText(R.string.track)) ) .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { mPoiManager.deleteTrack(id); ((SimpleCursorAdapter) getListAdapter()).getCursor().requery(); } }).setNegativeButton(R.string.no, null).create().show(); } else if(item.getItemId() == R.id.menu_exporttogpxpoi) { DoExportTrackGPX(id); } else if(item.getItemId() == R.id.menu_exporttokmlpoi) { DoExportTrackKML(id); } return super.onContextItemSelected(item); } private void DoExportTrackKML(int id) { dlgWait = Ut.ShowWaitDialog(this, 0); final int trackid = id; if(mThreadExecutor == null) mThreadExecutor = Executors.newSingleThreadExecutor(new SimpleThreadFactory("DoExportTrackKML")); this.mThreadExecutor.execute(new Runnable() { public void run() { final Track track = mPoiManager.getTrack(trackid); SimpleXML xml = new SimpleXML("kml"); xml.setAttr("xmlns:gx", "http://www.google.com/kml/ext/2.2"); xml.setAttr("xmlns", "http://www.opengis.net/kml/2.2"); SimpleXML Placemark = xml.createChild("Placemark"); Placemark.createChild("name").setText(track.Name); Placemark.createChild("description").setText(track.Descr); SimpleXML LineString = Placemark.createChild("LineString"); SimpleXML coordinates = LineString.createChild("coordinates"); StringBuilder builder = new StringBuilder(); for (TrackPoint tp : track.getPoints()){ builder.append(tp.lon).append(",").append(tp.lat).append(",").append(tp.alt).append(" "); } coordinates.setText(builder.toString().trim()); File folder = Ut.getRMapsExportDir(TrackListActivity.this); String filename = folder.getAbsolutePath() + "/track" + trackid + ".kml"; File file = new File(filename); FileOutputStream out; try { file.createNewFile(); out = new FileOutputStream(file); OutputStreamWriter wr = new OutputStreamWriter(out); wr.write(SimpleXML.saveXml(xml)); wr.close(); Message.obtain(mHandler, R.id.menu_exporttogpxpoi, 1, 0, filename).sendToTarget(); } catch (FileNotFoundException e) { Message.obtain(mHandler, R.id.menu_exporttogpxpoi, 0, 0, e.getMessage()).sendToTarget(); e.printStackTrace(); } catch (IOException e) { Message.obtain(mHandler, R.id.menu_exporttogpxpoi, 0, 0, e.getMessage()).sendToTarget(); e.printStackTrace(); } dlgWait.dismiss(); } }); } private void DoExportTrackGPX(int id) { dlgWait = Ut.ShowWaitDialog(this, 0); final int trackid = id; if(mThreadExecutor == null) mThreadExecutor = Executors.newSingleThreadExecutor(new SimpleThreadFactory("DoExportTrackGPX")); this.mThreadExecutor.execute(new Runnable() { public void run() { final Track track = mPoiManager.getTrack(trackid); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); SimpleXML xml = new SimpleXML("gpx"); xml.setAttr("xsi:schemaLocation", "http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd"); xml.setAttr("xmlns", "http://www.topografix.com/GPX/1/0"); xml.setAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); xml.setAttr("creator", "RMaps - http://code.google.com/p/robertprojects/"); xml.setAttr("version", "1.0"); xml.createChild("name").setText(track.Name); xml.createChild("desc").setText(track.Descr); SimpleXML trk = xml.createChild("trk"); SimpleXML trkseg = trk.createChild("trkseg"); SimpleXML trkpt = null; for (TrackPoint tp : track.getPoints()){ trkpt = trkseg.createChild("trkpt"); trkpt.setAttr("lat", Double.toString(tp.lat)); trkpt.setAttr("lon", Double.toString(tp.lon)); trkpt.createChild("ele").setText(Double.toString(tp.alt)); trkpt.createChild("time").setText(formatter.format(tp.date)); } File folder = Ut.getRMapsExportDir(TrackListActivity.this); String filename = folder.getAbsolutePath() + "/track" + trackid + ".gpx"; File file = new File(filename); FileOutputStream out; try { file.createNewFile(); out = new FileOutputStream(file); OutputStreamWriter wr = new OutputStreamWriter(out); wr.write(SimpleXML.saveXml(xml)); wr.close(); Message.obtain(mHandler, R.id.menu_exporttogpxpoi, 1, 0, filename).sendToTarget(); } catch (FileNotFoundException e) { Message.obtain(mHandler, R.id.menu_exporttogpxpoi, 0, 0, e.getMessage()).sendToTarget(); e.printStackTrace(); } catch (IOException e) { Message.obtain(mHandler, R.id.menu_exporttogpxpoi, 0, 0, e.getMessage()).sendToTarget(); e.printStackTrace(); } dlgWait.dismiss(); } }); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { mPoiManager.setTrackChecked((int)id); final CheckBox ch = (CheckBox) v.findViewById(R.id.checkbox); ch.setChecked(!ch.isChecked()); ((SimpleCursorAdapter) getListAdapter()).getCursor().requery(); super.onListItemClick(l, v, position, id); } }