Java tutorial
/* * Space Mapper * Copyright (C) 2012, 2013 John R.B. Palmer * Contact: jrpalmer@princeton.edu * * This file is part of Space Mapper. * * Space Mapper is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * * Space Mapper is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with Space Mapper. If not, see <http://www.gnu.org/licenses/>. */ package net.movelab.cmlibrary; import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Point; import android.location.Location; import android.location.LocationManager; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.support.v4.app.FragmentActivity; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapController; import com.google.android.maps.MapView; import com.google.android.maps.Overlay; import net.movelab.cmlibrary.Fix.Fixes; import net.movelab.cmlibrary.RangeSeekBar.OnRangeSeekBarChangeListener; import net.movelab.cmlibrary.RangeSeekBarDonut.OnRangeSeekBarDonutChangeListener; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; /** * Allows user to view their own data in a map (from the database on their phone * -- not from the server). * * @author John R.B. Palmer * * */ public class MapMyData extends FragmentActivity { String TAG = "MapMyData"; private MapView mapView; private MapController myMapController; public List<Overlay> mapOverlays; private TextView dateRangeText; boolean getIntro = false; boolean isPro = false; boolean loadingData; boolean updatingDatabase; boolean savingCsv; private long startTime; private long endTime; private RelativeLayout dateArea; public static String DATES_BUTTON_MESSAGE = "datesButtonMessage"; GeoPoint point; boolean satToggle; String stringLat; String stringLng; String stringAlt; String stringAcc; String stringProvider; String stringTime; boolean shareData; Double lastLat = null; Double lastLon = null; Double lastGeoLat = null; Double lastGeoLon = null; int startDay; int startMonth; int startYear; int endDay; int endMonth; int endYear; private int lastRecId = 0; public static boolean reloadData = false; boolean drawConfidenceCircles; boolean drawIcons; // TODO setting this totrue for testing until I build the on/off button boolean selectNewPrivacyZone = true; ArrayList<GeoPoint> privacyZones; boolean isServiceOn; GeoPoint currentCenter; MapOverlay mainOverlay; int BORDER_COLOR_MAP = 0xee4D2EFF; int FILL_COLOR_MAP = 0x554D2EFF; int BORDER_COLOR_SAT = 0xeeD9FCFF; int FILL_COLOR_SAT = 0xbbD9FCFF; int PZ_BORDER_COLOR = 0xee00ff00; int PZ_FILL_COLOR = 0x5500ff00; ProgressBar progressbar; ArrayList<MapPoint> mPoints; MapPoint[] mPointsArray; TextView progressbarText; LinearLayout progressNotificationArea; LinearLayout receiverNotificationArea; private TextView mReceiversOffWarning; boolean _mustDraw = true; long thumbMin = -1; long thumbMax = -1; private int minDist = 0; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); final int screenSize = getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK; if (screenSize != Configuration.SCREENLAYOUT_SIZE_LARGE && screenSize != Configuration.SCREENLAYOUT_SIZE_XLARGE) requestWindowFeature(Window.FEATURE_NO_TITLE); // TODO add all of the alerts from countdown activity regarding sensors // off, sm off etc. Context context = getApplicationContext(); PropertyHolder.init(context); PowerSensor.init(context); if (Util.trafficCop(this)) finish(); if (!PropertyHolder.getInitialStartDateSet()) { Calendar now = Calendar.getInstance(); now.setTimeInMillis(System.currentTimeMillis()); PropertyHolder.setMapStartDate(now); PropertyHolder.setInitialStartDateSet(true); } minDist = Util.getMinDist(); // Log.e("FixGet", "minDist=" + minDist); setContentView(R.layout.map_layout); mapView = (MapView) findViewById(R.id.mapview); mapView.setBuiltInZoomControls(true); // pauseToggle = !PropertyHolder.isServiceOn(); mPoints = new ArrayList<MapPoint>(); myMapController = mapView.getController(); myMapController.setZoom(15); progressbar = (ProgressBar) findViewById(R.id.mapProgressbar); progressbar.setProgress(0); progressbarText = (TextView) findViewById(R.id.progressBarLabel); progressNotificationArea = (LinearLayout) findViewById(R.id.mapProgressNotificationArea); receiverNotificationArea = (LinearLayout) findViewById(R.id.mapReceiverNotificationArea); mReceiversOffWarning = (TextView) findViewById(R.id.mapReceiversOffWarning); dateArea = (RelativeLayout) findViewById(R.id.dateArea); dateRangeText = (TextView) findViewById(R.id.dateSelectionText); dateRangeText.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent e) { if (e.getAction() == MotionEvent.ACTION_DOWN) { dateRangeText.setBackgroundResource(R.drawable.red_border_pressed); } if (e.getAction() == MotionEvent.ACTION_UP) { dateRangeText.setBackgroundResource(R.drawable.red_border); } return false; } }); dateRangeText.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { Intent i = new Intent(MapMyData.this, Settings.class); i.putExtra(DATES_BUTTON_MESSAGE, true); startActivity(i); } }); getIntro = PropertyHolder.getIntro(); isPro = PropertyHolder.getProVersion(); AppRater.app_launched(this); privacyZones = new ArrayList<GeoPoint>(); } @Override protected boolean isRouteDisplayed() { // TODO Auto-generated method stub return false; } public class FixReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getBooleanExtra(FixGet.NEW_RECORD, false) == true) { updateMap(intent); } } } public void updateMap(Intent intent) { Context context = getApplicationContext(); if (loadingData == false) { loadingData = true; new DataGrabberTask().execute(context); } } FixReceiver fixReceiver; @Override protected void onResume() { Context context = getApplicationContext(); Log.e("TAPMAP", "selectPZ=" + selectNewPrivacyZone); if (Util.trafficCop(this)) finish(); dateRangeText.setBackgroundResource(R.drawable.red_border); if (reloadData) { mPoints.clear(); lastRecId = 0; } isServiceOn = PropertyHolder.isServiceOn(); shareData = PropertyHolder.getShareData(); drawConfidenceCircles = PropertyHolder.getMapAcc(); drawIcons = PropertyHolder.getMapIcons(); satToggle = PropertyHolder.getMapSat(); mapView.setSatellite(satToggle); if (PropertyHolder.getLimitEndDate()) dateRangeText.setText(Util.userDate(PropertyHolder.getMapStartDate()) + " - " + Util.userDate(PropertyHolder.getMapEndDate())); else dateRangeText.setText(Util.userDate(PropertyHolder.getMapStartDate()) + " - " + getResources().getString(R.string.present)); if (Util.needDatabaseUpdate) { progressbarText.setText(getResources().getString(R.string.database_updating_text)); if (updatingDatabase == false) { updatingDatabase = true; new DatabaseUpdateTask().execute(context); } } else { progressNotificationArea.setVisibility(View.VISIBLE); progressbarText.setText(getResources().getString(R.string.mapdata_loading_text)); if (loadingData == false) { loadingData = true; new DataGrabberTask().execute(context); } } receiverNotificationArea.setVisibility(View.INVISIBLE); if (isServiceOn) { final LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { if (!manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) { receiverNotificationArea.setVisibility(View.VISIBLE); mReceiversOffWarning.setText(getResources().getString(R.string.noGPSnoNet)); } else { receiverNotificationArea.setVisibility(View.VISIBLE); mReceiversOffWarning.setText(getResources().getString(R.string.noGPS)); } mReceiversOffWarning.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)); } }); } } else { receiverNotificationArea.setVisibility(View.VISIBLE); mReceiversOffWarning.setText(getResources().getString(R.string.main_text_off)); mReceiversOffWarning.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent e) { if (e.getAction() == MotionEvent.ACTION_DOWN) { receiverNotificationArea .setBackgroundColor(getResources().getColor(R.color.push_button_color)); } if (e.getAction() == MotionEvent.ACTION_UP) { receiverNotificationArea.setBackgroundColor(getResources().getColor(R.color.dark_grey)); } return false; } }); mReceiversOffWarning.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(getString(R.string.internal_message_id) + Util.MESSAGE_SCHEDULE); sendBroadcast(intent); receiverNotificationArea.setVisibility(View.INVISIBLE); } }); } IntentFilter fixFilter; fixFilter = new IntentFilter( getResources().getString(R.string.internal_message_id) + Util.MESSAGE_FIX_RECORDED); fixReceiver = new FixReceiver(); registerReceiver(fixReceiver, fixFilter); super.onResume(); } @Override protected void onPause() { unregisterReceiver(fixReceiver); super.onPause(); } static final private int LOCATE_NOW = Menu.FIRST; static final private int LIST_DATA = Menu.FIRST + 1; static final private int SAVE_MAP = Menu.FIRST + 2; static final private int SHARE_MAP = Menu.FIRST + 3; static final private int LIFELINE = Menu.FIRST + 4; static final private int SETTINGS = Menu.FIRST + 5; static final private int SAVE_CSV = Menu.FIRST + 6; static final private int ABOUT = Menu.FIRST + 7; static final private int RATE = Menu.FIRST + 8; static final private int SHARE = Menu.FIRST + 9; static final private int FLUSH_GPS = Menu.FIRST + 10; static final private int ASP = Menu.FIRST + 11; static final private int CENTER = Menu.FIRST + 13; @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); menu.clear(); menu.add(0, LOCATE_NOW, Menu.NONE, R.string.menu_locate_now); menu.add(0, SETTINGS, Menu.NONE, R.string.menu_settings); menu.add(0, CENTER, Menu.NONE, R.string.menu_center_map); menu.add(0, SAVE_MAP, Menu.NONE, R.string.menu_map_save); menu.add(0, SHARE_MAP, Menu.NONE, R.string.menu_map_share); menu.add(0, LIFELINE, Menu.NONE, R.string.lifeline_button); menu.add(0, LIST_DATA, Menu.NONE, R.string.list_data_button); menu.add(0, SAVE_CSV, Menu.NONE, R.string.save_data_button); menu.add(0, FLUSH_GPS, Menu.NONE, R.string.menu_flush_gps); menu.add(0, RATE, Menu.NONE, R.string.menu_rate); menu.add(0, SHARE, Menu.NONE, R.string.menu_share); if (shareData) menu.add(0, ASP, Menu.NONE, R.string.menu_asp); menu.add(0, ABOUT, Menu.NONE, R.string.about); return true; } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item); Context context = getApplicationContext(); switch (item.getItemId()) { case (ASP): { Intent i = new Intent(this, Help.class); // start the intent startActivity(i); return true; } case (SAVE_CSV): { if (savingCsv == false) { savingCsv = true; new SaveCsvTask().execute(context); } return true; } case (LIST_DATA): { Intent i = new Intent(this, ListMyDataCursorLoader.class); startActivity(i); return true; } case (LIFELINE): { // create an intent object and tell it where to go Intent i = new Intent(this, Lifeline.class); // start the intent startActivity(i); return true; } case (LOCATE_NOW): { if (Util.locatingNow == false) { Intent i = new Intent(MapMyData.this, FixGet.class); startService(i); } return true; } case (FLUSH_GPS): { buildFlushGPSAlert(); return true; } case (CENTER): { if (currentCenter != null) { myMapController.animateTo(currentCenter); } return true; } case (SAVE_MAP): { saveMapImage(context); return true; } case (SHARE_MAP): { shareMap(context); return true; } case (SETTINGS): { Intent i = new Intent(this, Settings.class); startActivity(i); return true; } case (ABOUT): { Intent i = new Intent(this, About.class); // start the intent startActivity(i); return true; } case (RATE): { AppRater.showRateDialog(this, null); return true; } case (SHARE): { Intent shareIntent = new Intent(Intent.ACTION_SEND); // set the type shareIntent.setType("text/plain"); // add a subject shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Space Mapper"); // build the body of the message to be shared String shareMessage = "https://play.google.com/store/apps/details?id=" + getResources().getString(R.string.package_name); // add the message shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, shareMessage); // start the chooser for sharing startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.share_with))); return true; } } return false; } /* * Draw selected locations on map. Returns true if drawn; false otherwise. */ private boolean drawFixes(ArrayList<MapPoint> data, long minTimeSelection, long maxTimeSelection, boolean sat, boolean clearMapOverlays, boolean recenter) { int nData = data.size(); // quick return if the maximum time selected is less than the minimum // time selected or if there is no data loaded if (maxTimeSelection - minTimeSelection < 0 || nData < 1) { // get and clear mapview overlays mapOverlays = mapView.getOverlays(); if (clearMapOverlays) mapOverlays.clear(); mapView.postInvalidate(); return false; } // turn data into array and grab long arrays of entry and exit times // from data MapPoint[] dataArray = new MapPoint[nData]; long[] entryTimes = new long[nData]; long[] exitTimes = new long[nData]; int i = 0; for (MapPoint p : data) { dataArray[i] = p.copy(); entryTimes[i] = p.entryTime; exitTimes[i] = p.exitTime; i++; } // calculate indexes for min and max times; if -1 is passed for min time // selection, then min index is simply 0; if -1 passed for max time // selection, then max index is the last element in the data array. int maxTimeIndex = maxTimeSelection == -1 ? (nData - 1) : Util.maxElementLessThanOrEqualToKey(entryTimes, maxTimeSelection, 0, (nData - 1)); int minTimeIndex = minTimeSelection == -1 ? 0 : Util.minElementGreaterThanOrEqualToKey(exitTimes, minTimeSelection, 0, (nData - 1)); // calculate the number of elements between these two index values int nSelected = 1 + maxTimeIndex - minTimeIndex; // return if there are no elements selected (indicated either by // nSelected less than 1 or by the min or max time index functions // returning -1 if (nSelected < 1 || minTimeIndex < 0 || maxTimeIndex < 0) { // get and clear mapview overlays mapOverlays = mapView.getOverlays(); if (clearMapOverlays) mapOverlays.clear(); mapView.postInvalidate(); return false; } // create new array of the selected points (which will be actually // drawn) and copy the selected points into this array MapPoint[] mPointsSelected = new MapPoint[nSelected]; System.arraycopy(dataArray, minTimeIndex, mPointsSelected, 0, nSelected); // flag most recent fix for special icon mPointsSelected[nSelected - 1].setIconFlag(MapPoint.ICON_CURRENT_LOCATION); // get mapview overlays mapOverlays = mapView.getOverlays(); // Clear any existing overlays if cleraMapOverlays set to true if (clearMapOverlays) mapOverlays.clear(); // set colors depending on satellite background int BC = sat ? BORDER_COLOR_SAT : BORDER_COLOR_MAP; int FC = sat ? FILL_COLOR_SAT : FILL_COLOR_MAP; mainOverlay = new MapOverlay(BC, FC); mainOverlay.setPointsToDraw(mPointsSelected); mapOverlays.add(mainOverlay); mapView.postInvalidate(); currentCenter = new GeoPoint(mPointsSelected[nSelected - 1].lat, mPointsSelected[nSelected - 1].lon); if (recenter) myMapController.animateTo(currentCenter); return true; } private Bitmap getMapImage() { mapView.setDrawingCacheEnabled(true); Bitmap bmp = Bitmap.createBitmap(mapView.getDrawingCache()); mapView.setDrawingCacheEnabled(false); return bmp; } private void saveMapImage(Context context) { try { File root = Environment.getExternalStorageDirectory(); File directory = new File(root, "SpaceMapper"); directory.mkdirs(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); Date date = new Date(); String stringDate = dateFormat.format(date); String filename = getResources().getString(R.string.filenameprefix_map) + stringDate + ".jpg"; if (directory.canWrite()) { File f = new File(directory, filename); FileOutputStream out = new FileOutputStream(f); Bitmap bmp = getMapImage(); bmp.compress(Bitmap.CompressFormat.JPEG, 100, out); out.close(); Util.toast(context, getResources().getString(R.string.data_saved) + " " + f); } else { Util.toast(context, getResources().getString(R.string.data_SD_unavailable)); } } catch (IOException e) { Util.toast(context, getResources().getString(R.string.data_SD_error)); } } private void shareMap(Context context) { try { File root = Environment.getExternalStorageDirectory(); File directory = new File(root, "SpaceMapper"); directory.mkdirs(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); Date date = new Date(); String stringDate = dateFormat.format(date); String filename = getResources().getString(R.string.filenameprefix_map) + stringDate + ".jpg"; if (directory.canWrite()) { File f = new File(directory, filename); FileOutputStream out = new FileOutputStream(f); Bitmap bmp = getMapImage(); bmp.compress(Bitmap.CompressFormat.JPEG, 100, out); out.close(); Intent share = new Intent(Intent.ACTION_SEND); share.setType("image/jpeg"); share.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f)); // add the message share.putExtra(android.content.Intent.EXTRA_TEXT, getResources().getText(R.string.made_with_SM) + ": https://play.google.com/store/apps/details?id=" + getResources().getString(R.string.package_name)); startActivity(Intent.createChooser(share, getResources().getText(R.string.share_with))); } else { Util.toast(context, getResources().getString(R.string.data_SD_unavailable)); } } catch (IOException e) { Util.toast(context, getResources().getString(R.string.data_SD_error)); } } class MapOverlay extends Overlay { private Paint mPaintBorder; private Paint mPaintFill; private Paint mPaintPzBorder; private Paint mPaintPzFill; private Bitmap normalfixPin; private Bitmap currentfixPin; private MapPoint[] pointsToDraw; MapOverlay(int border, int fill) { mPaintBorder = new Paint(); mPaintBorder.setStyle(Paint.Style.STROKE); mPaintBorder.setAntiAlias(true); mPaintBorder.setColor(border); mPaintFill = new Paint(); mPaintFill.setStyle(Paint.Style.FILL); mPaintFill.setColor(fill); mPaintPzBorder = new Paint(); mPaintPzBorder.setStyle(Paint.Style.STROKE); mPaintPzBorder.setAntiAlias(true); mPaintPzBorder.setColor(PZ_BORDER_COLOR); mPaintPzFill = new Paint(); mPaintPzFill.setStyle(Paint.Style.FILL); mPaintPzFill.setColor(PZ_FILL_COLOR); normalfixPin = BitmapFactory.decodeResource(getResources(), R.drawable.old_fix_pin); currentfixPin = BitmapFactory.decodeResource(getResources(), R.drawable.new_fix_pin); } public void setPointsToDraw(MapPoint[] points) { pointsToDraw = points; } public MapPoint[] getPointsToDraw() { return pointsToDraw; } @Override public void draw(Canvas canvas, MapView mapView, boolean shadow) { super.draw(canvas, mapView, shadow); if (shadow) return; // First draw confidence circles if toggled if (drawConfidenceCircles) { for (MapPoint p : pointsToDraw) { // convert point to pixels Point screenPts = new Point(); GeoPoint pointToDraw = new GeoPoint(p.lat, p.lon); mapView.getProjection().toPixels(pointToDraw, screenPts); int radius = (int) mapView.getProjection().metersToEquatorPixels(p.acc); canvas.drawCircle(screenPts.x, screenPts.y, radius, mPaintBorder); canvas.drawCircle(screenPts.x, screenPts.y, radius, mPaintFill); } } // Now draw icons if (drawIcons) { for (MapPoint p : pointsToDraw) { // convert point to pixels Point screenPts = new Point(); GeoPoint pointToDraw = new GeoPoint(p.lat, p.lon); mapView.getProjection().toPixels(pointToDraw, screenPts); if (p.iconFlag == MapPoint.ICON_NORMAL) canvas.drawBitmap(normalfixPin, screenPts.x - normalfixPin.getWidth() / 2, screenPts.y - normalfixPin.getHeight(), null); else canvas.drawBitmap(currentfixPin, screenPts.x - currentfixPin.getWidth() / 2, screenPts.y - currentfixPin.getHeight(), null); } } Log.e("TAPMAP", "pzs.size=" + privacyZones.size()); if (privacyZones != null && privacyZones.size() > 0) { for (GeoPoint p : privacyZones) { Point screenPts = new Point(); mapView.getProjection().toPixels(p, screenPts); int radius = (int) mapView.getProjection().metersToEquatorPixels(Util.PRIVACY_ZONE_RADIUS); canvas.drawCircle(screenPts.x, screenPts.y, radius, mPaintPzBorder); canvas.drawCircle(screenPts.x, screenPts.y, radius, mPaintPzFill); Log.i("TAPMAP", "just drew pz"); } } return; } @Override public boolean onTap(GeoPoint p, MapView mapview) { if (selectNewPrivacyZone) { privacyZones.add(new GeoPoint(p.getLatitudeE6(), p.getLongitudeE6())); Log.i("TAPMAP", "tapped: " + p.getLatitudeE6()); return true; } else { return false; } } } public class DataGrabberTask extends AsyncTask<Context, Integer, Boolean> { int myProgress; int nFixes; ArrayList<MapPoint> results = new ArrayList<MapPoint>(); GeoPoint center; @Override protected void onPreExecute() { myProgress = 0; } protected Boolean doInBackground(Context... context) { results.clear(); startTime = PropertyHolder.getMapStartDate().getTime(); endTime = PropertyHolder.getMapEndDate().getTime(); final String selectionString; final boolean limitStart = PropertyHolder.getLimitStartDate(); final boolean limitEnd = PropertyHolder.getLimitEndDate(); if (limitStart && !limitEnd) selectionString = Fixes.KEY_ROWID + " > " + lastRecId + " AND " + Fixes.KEY_STATION_DEPARTURE_TIMELONG + " >= " + startTime; else if (!limitStart && limitEnd) selectionString = Fixes.KEY_ROWID + " > " + lastRecId + " AND " + Fixes.KEY_TIMELONG + " <= " + endTime; else if (limitStart && limitEnd) selectionString = Fixes.KEY_ROWID + " > " + lastRecId + " AND " + Fixes.KEY_STATION_DEPARTURE_TIMELONG + " >= " + startTime + " AND " + Fixes.KEY_TIMELONG + " <= " + endTime; else selectionString = Fixes.KEY_ROWID + " > " + lastRecId; ContentResolver cr = getContentResolver(); Cursor c = cr.query(Util.getFixesUri(context[0]), Fixes.KEYS_LATLONACCTIMES, selectionString, null, null); if (!c.moveToFirst()) { c.close(); return false; } int latCol = c.getColumnIndexOrThrow("latitude"); int lonCol = c.getColumnIndexOrThrow("longitude"); int accCol = c.getColumnIndexOrThrow("accuracy"); int idCol = c.getColumnIndexOrThrow("_id"); int timeCol = c.getColumnIndexOrThrow(Fixes.KEY_TIMELONG); int sdtimeCol = c.getColumnIndexOrThrow(Fixes.KEY_STATION_DEPARTURE_TIMELONG); nFixes = c.getCount(); // float lastAcc = 0; int currentRecord = 0; while (!c.isAfterLast()) { myProgress = (int) (((currentRecord + 1) / (float) nFixes) * 100); publishProgress(myProgress); // Escape early if cancel() is called if (isCancelled()) break; lastRecId = c.getInt(idCol); // First grabbing double values of lat lon and time Double lat = c.getDouble(latCol); Double lon = c.getDouble(lonCol); float acc = c.getFloat(accCol); long entryTime = c.getLong(timeCol); long exitTime = c.getLong(sdtimeCol); Double geoLat = lat * 1E6; Double geoLon = lon * 1E6; results.add(new MapPoint(geoLat.intValue(), geoLon.intValue(), acc, entryTime, exitTime, MapPoint.ICON_NORMAL)); c.moveToNext(); currentRecord++; } c.close(); return true; } protected void onProgressUpdate(Integer... progress) { progressbar.setProgress(progress[0]); } protected void onPostExecute(Boolean result) { Context context = getApplicationContext(); if (result) { if (results != null && results.size() > 0) { for (MapPoint p : results) { mPoints.add(p); } final int newlastFixIndex = mPoints.size() - 1; final long selectorEndTime; if (PropertyHolder.getLimitEndDate()) { selectorEndTime = Long.valueOf(endTime); } else { selectorEndTime = Long.valueOf(mPoints.get(newlastFixIndex).exitTime); } drawDateSelector(startTime, selectorEndTime, context); } } else drawDateSelector(startTime, endTime, context); progressNotificationArea.setVisibility(View.INVISIBLE); dateArea.setVisibility(View.VISIBLE); loadingData = false; if (getIntro && !isPro) { PropertyHolder.setIntro(false); getIntro = false; buildAlertMessageIntro(); } } } public class DatabaseUpdateTask extends AsyncTask<Context, Integer, Boolean> { int myProgress; @Override protected void onPreExecute() { myProgress = 0; progressNotificationArea.setVisibility(View.VISIBLE); } protected Boolean doInBackground(Context... context) { Double lastLat = null; Double lastLon = null; ContentResolver cr = getContentResolver(); Cursor c = cr.query(Util.getFixesUri(context[0]), Fixes.KEYS_LATLONTIME, null, null, null); if (!c.moveToFirst()) { c.close(); return false; } int latCol = c.getColumnIndexOrThrow(Fixes.KEY_LATITUDE); int lonCol = c.getColumnIndexOrThrow(Fixes.KEY_LONGITUDE); int idCol = c.getColumnIndexOrThrow(Fixes.KEY_ROWID); int timelongCol = c.getColumnIndexOrThrow(Fixes.KEY_TIMELONG); int nFixes = c.getCount(); int currentRecord = 0; while (!c.isAfterLast()) { myProgress = (int) (((currentRecord + 1) / (float) nFixes) * 100); publishProgress(myProgress); // Escape early if cancel() is called if (isCancelled()) break; // First grabbing double values of lat lon and time Double lat = c.getDouble(latCol); Double lon = c.getDouble(lonCol); int id = c.getInt(idCol); if (lastLat == null && lastLon == null) { lastLat = lat; lastLon = lon; } else if (lat != null && lon != null && lastLat != null && lastLon != null) { float[] distResult = new float[1]; Location.distanceBetween(lastLat, lastLon, lat, lon, distResult); float dist = distResult[0]; if (dist < minDist) { if (id > 1) { ContentValues cv = new ContentValues(); String sc = Fixes.KEY_ROWID + " = " + (id - 1); cv.put(Fixes.KEY_STATION_DEPARTURE_TIMELONG, c.getLong(timelongCol)); cr.update(Util.getFixesUri(context[0]), cv, sc, null); } cr.delete(Util.getFixesUri(context[0]), Fixes.KEY_ROWID + " = " + id, null); } else { lastLat = lat; lastLon = lon; ContentValues cv = new ContentValues(); String sc = Fixes.KEY_ROWID + " = " + id; cv.put(Fixes.KEY_STATION_DEPARTURE_TIMELONG, c.getLong(timelongCol)); cr.update(Util.getFixesUri(context[0]), cv, sc, null); } } c.moveToNext(); currentRecord++; } c.close(); return true; } protected void onProgressUpdate(Integer... progress) { progressbar.setProgress(progress[0]); } protected void onPostExecute(Boolean result) { Util.needDatabaseUpdate = false; PropertyHolder.setNeedDatabaseValueUpdate(false); progressbarText.setText(getResources().getString(R.string.mapdata_loading_text)); Context context = getApplicationContext(); updatingDatabase = false; if (loadingData == false) { loadingData = true; new DataGrabberTask().execute(context); } } } public class SaveCsvTask extends AsyncTask<Context, Integer, Boolean> { int myProgress; String saveMe; File file; private int FLAG; private final static int SAVED = 1; private final static int SD_UNAVAILABLE = 2; private final static int SD_ERROR = 3; @Override protected void onPreExecute() { progressbarText.setText(getResources().getString(R.string.saving_data)); progressNotificationArea.setVisibility(View.VISIBLE); myProgress = 0; } protected Boolean doInBackground(Context... context) { ContentResolver cr = getContentResolver(); Cursor c = cr.query(Util.getFixesUri(context[0]), Fixes.KEYS_SAVECSV, null, null, null); int accuracy = c.getColumnIndexOrThrow(Fixes.KEY_ACCURACY); int altitude = c.getColumnIndexOrThrow(Fixes.KEY_ALTITUDE); int latitude = c.getColumnIndexOrThrow(Fixes.KEY_LATITUDE); int longitude = c.getColumnIndexOrThrow(Fixes.KEY_LONGITUDE); int provider = c.getColumnIndexOrThrow(Fixes.KEY_PROVIDER); int timelong = c.getColumnIndexOrThrow(Fixes.KEY_TIMELONG); StringBuilder sb = new StringBuilder(""); sb.append("accuracy").append(","); sb.append("altitude").append(","); sb.append("latitude").append(","); sb.append("longitude").append(","); sb.append("provider").append(","); sb.append("time"); c.moveToFirst(); int nFixes = c.getCount(); int currentRecord = 0; while (!c.isAfterLast()) { myProgress = (int) (((currentRecord + 1) / (float) nFixes) * 100); publishProgress(myProgress); // Escape early if cancel() is called if (isCancelled()) break; sb.append("\n"); sb.append(Util.doubleFieldVal(c, accuracy)).append(","); sb.append(Util.doubleFieldVal(c, altitude)).append(","); sb.append(Util.doubleFieldVal(c, latitude)).append(","); sb.append(Util.doubleFieldVal(c, longitude)).append(","); sb.append(Util.enquote(c.getString(provider))).append(","); sb.append(Util.enquote(Util.userDate(new Date(c.getLong(timelong))).trim())); c.moveToNext(); currentRecord++; } saveMe = sb.toString(); c.close(); BufferedWriter out; try { File root = Environment.getExternalStorageDirectory(); File directory = new File(root, "SpaceMapper"); directory.mkdirs(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); Date date = new Date(); String stringDate = dateFormat.format(date); String filename = getResources().getString(R.string.filenameprefix_csv) + stringDate + ".csv"; if (directory.canWrite()) { file = new File(directory, filename); FileWriter filewriter = new FileWriter(file); out = new BufferedWriter(filewriter); out.write(saveMe); out.close(); FLAG = SAVED; } else { FLAG = SD_UNAVAILABLE; } } catch (IOException e) { FLAG = SD_ERROR; } return true; } protected void onProgressUpdate(Integer... progress) { progressbar.setProgress(progress[0]); } protected void onPostExecute(Boolean result) { Context context = getApplicationContext(); switch (FLAG) { case (SAVED): { Util.toast(context, getResources().getString(R.string.data_saved) + " " + file); break; } case (SD_UNAVAILABLE): { Util.toast(context, getResources().getString(R.string.data_SD_unavailable)); break; } case (SD_ERROR): { Util.toast(context, getResources().getString(R.string.data_SD_error)); break; } } progressNotificationArea.setVisibility(View.INVISIBLE); savingCsv = false; } } private void buildFlushGPSAlert() { final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage(getResources().getString(R.string.renew_gps_alert)).setCancelable(true) .setPositiveButton(getResources().getString(R.string.ok), new DialogInterface.OnClickListener() { public void onClick(final DialogInterface dialog, final int id) { Util.flushGPSFlag = true; dialog.cancel(); } }) .setNegativeButton(getResources().getString(R.string.cancel), new DialogInterface.OnClickListener() { public void onClick(final DialogInterface dialog, final int id) { dialog.cancel(); } }); final AlertDialog alert = builder.create(); alert.show(); } private void buildAlertMessageIntro() { final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage(getResources().getText(R.string.main_text)).setCancelable(true) .setNeutralButton(getResources().getString(R.string.ok), new DialogInterface.OnClickListener() { public void onClick(final DialogInterface dialog, final int id) { dialog.dismiss(); } }); final AlertDialog alert = builder.create(); alert.show(); } private void drawDateSelector(long min, long max, Context context) { final long barMax = max; final long barMin = min; final long selectedMax; final long selectedMin; if (thumbMin == -1 || thumbMin < min) selectedMin = Long.valueOf(min); else selectedMin = Long.valueOf(thumbMin); if (thumbMax == -1 || thumbMax > max) selectedMax = Long.valueOf(max); else selectedMax = Long.valueOf(thumbMax); drawFixes(mPoints, selectedMin, selectedMax, satToggle, true, true); if (PropertyHolder.getLimitEndDate()) dateRangeText .setText(Util.userDate(new Date(selectedMin)) + " - " + Util.userDate(new Date(selectedMax))); else dateRangeText.setText( Util.userDate(new Date(selectedMin)) + " - " + getResources().getString(R.string.present)); if (Build.VERSION.SDK_INT >= 5) { RangeSeekBar<Long> seekBar = new RangeSeekBar<Long>(min, max, context); seekBar.setSelectedMinValue(selectedMin); seekBar.setSelectedMaxValue(selectedMax); seekBar.setNotifyWhileDragging(true); seekBar.setOnRangeSeekBarChangeListener(new OnRangeSeekBarChangeListener<Long>() { @Override public void onRangeSeekBarValuesChanged(RangeSeekBar<?> bar, Long minValue, Long maxValue) { drawFixes(mPoints, minValue, maxValue, satToggle, true, false); if (maxValue < barMax) { thumbMax = Long.valueOf(maxValue); dateRangeText.setText( Util.userDate(new Date(minValue)) + " - " + Util.userDate(new Date(maxValue))); } else { thumbMax = -1; if (PropertyHolder.getLimitEndDate()) dateRangeText.setText( Util.userDate(new Date(minValue)) + " - " + Util.userDate(new Date(maxValue))); else dateRangeText.setText(Util.userDate(new Date(minValue)) + " - " + getResources().getString(R.string.present)); } } }); // add RangeSeekBar to pre-defined layout LinearLayout dateSelectorArea = (LinearLayout) findViewById(R.id.dateSelectorArea); dateSelectorArea.removeAllViews(); dateSelectorArea.addView(seekBar); } else { RangeSeekBarDonut<Long> seekBar = new RangeSeekBarDonut<Long>(min, max, context); seekBar.setSelectedMinValue(selectedMin); seekBar.setSelectedMaxValue(selectedMax); seekBar.setNotifyWhileDragging(true); seekBar.setOnRangeSeekBarDonutChangeListener(new OnRangeSeekBarDonutChangeListener<Long>() { @Override public void onRangeSeekBarDonutValuesChanged(RangeSeekBarDonut<?> bar, Long minValue, Long maxValue) { drawFixes(mPoints, minValue, maxValue, satToggle, true, false); if (maxValue < barMax) { thumbMax = Long.valueOf(maxValue); dateRangeText.setText( Util.userDate(new Date(minValue)) + " - " + Util.userDate(new Date(maxValue))); } else { thumbMax = -1; if (PropertyHolder.getLimitEndDate()) dateRangeText.setText( Util.userDate(new Date(minValue)) + " - " + Util.userDate(new Date(maxValue))); else dateRangeText.setText(Util.userDate(new Date(minValue)) + " - " + getResources().getString(R.string.present)); } } }); // add RangeSeekBar to pre-defined layout LinearLayout dateSelectorArea = (LinearLayout) findViewById(R.id.dateSelectorArea); dateSelectorArea.removeAllViews(); dateSelectorArea.addView(seekBar); } } }