diff --git a/README.md b/README.md index 35827008..4ec49567 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -[Get it on Google Play](https://play.google.com/store/apps/details?id=org.osmtracker) -[Get it on F-Droid](https://f-droid.org/app/org.osmtracker) +[Get it on Google Play](https://play.google.com/store/apps/details?id=net.osmtracker) +[Get it on F-Droid](https://f-droid.org/app/net.osmtracker) -OSMTracker for Androidâ„¢ official source code repository is [https://github.com/nguillaumin/osmtracker-android](https://github.com/nguillaumin/osmtracker-android). +OSMTracker for Androidâ„¢ official source code repository is [https://github.com/labexp/osmtracker-android](https://github.com/labexp/osmtracker-android). -[![Build Status](https://travis-ci.org/nguillaumin/osmtracker-android.svg?branch=master)](https://travis-ci.org/nguillaumin/osmtracker-android) +[![Build Status](https://travis-ci.org/labexp/osmtracker-android.svg?branch=master)](https://travis-ci.org/labexp/osmtracker-android) -For more information about the project, documentation and bug reports please visit https://github.com/nguillaumin/osmtracker-android/wiki +For more information about the project, documentation and bug reports please visit https://github.com/labexp/osmtracker-android/wiki To help translate OSMTracker, please visit https://www.transifex.com/projects/p/osmtracker-android/ diff --git a/app/build.gradle b/app/build.gradle index 0c1fef6d..bb4a1805 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,12 +7,12 @@ android { buildToolsVersion "27.0.3" defaultConfig { - applicationId "org.osmtracker" - minSdkVersion 8 - targetSdkVersion 16 + applicationId "net.osmtracker" + minSdkVersion 11 + targetSdkVersion 26 multiDexEnabled true - testApplicationId "org.osmtracker.test" + testApplicationId "net.osmtracker.test" testInstrumentationRunner "android.test.InstrumentationTestRunner" } @@ -61,6 +61,7 @@ dependencies { implementation 'org.osmdroid:osmdroid-android:5.6.5' implementation 'oauth.signpost:signpost-commonshttp4:1.2.1.2' implementation 'org.slf4j:slf4j-android:1.7.25' + implementation 'com.android.support:support-v4:23.0.0' } task copyNorwegianValues(type: Copy) { diff --git a/app/src/androidTest/java/org/osmtracker/test/activity/OSMUploadTest.java b/app/src/androidTest/java/net/osmtracker/test/activity/OSMUploadTest.java similarity index 72% rename from app/src/androidTest/java/org/osmtracker/test/activity/OSMUploadTest.java rename to app/src/androidTest/java/net/osmtracker/test/activity/OSMUploadTest.java index ae696bcd..1f1af44c 100644 --- a/app/src/androidTest/java/org/osmtracker/test/activity/OSMUploadTest.java +++ b/app/src/androidTest/java/net/osmtracker/test/activity/OSMUploadTest.java @@ -1,13 +1,13 @@ -package org.osmtracker.test.activity; +package net.osmtracker.test.activity; -import org.osmtracker.activity.OpenStreetMapUpload; +import net.osmtracker.activity.OpenStreetMapUpload; import android.test.ActivityInstrumentationTestCase2; public class OSMUploadTest extends ActivityInstrumentationTestCase2 { public OSMUploadTest() { - super("org.osmtracker", OpenStreetMapUpload.class); + super("net.osmtracker", OpenStreetMapUpload.class); } @Override diff --git a/app/src/androidTest/java/org/osmtracker/test/activity/TrackDetailTest.java b/app/src/androidTest/java/net/osmtracker/test/activity/TrackDetailTest.java similarity index 79% rename from app/src/androidTest/java/org/osmtracker/test/activity/TrackDetailTest.java rename to app/src/androidTest/java/net/osmtracker/test/activity/TrackDetailTest.java index ef8c09a8..17810990 100644 --- a/app/src/androidTest/java/org/osmtracker/test/activity/TrackDetailTest.java +++ b/app/src/androidTest/java/net/osmtracker/test/activity/TrackDetailTest.java @@ -1,11 +1,11 @@ -package org.osmtracker.test.activity; +package net.osmtracker.test.activity; import junit.framework.Assert; -import org.osmtracker.activity.TrackDetail; -import org.osmtracker.db.TrackContentProvider; -import org.osmtracker.db.TrackContentProvider.Schema; -import org.osmtracker.test.util.MockData; +import net.osmtracker.activity.TrackDetail; +import net.osmtracker.db.TrackContentProvider; +import net.osmtracker.db.TrackContentProvider.Schema; +import net.osmtracker.test.util.MockData; import android.content.ContentResolver; import android.content.ContentUris; @@ -22,7 +22,7 @@ public class TrackDetailTest extends ActivityInstrumentationTestCase2 { @@ -30,7 +30,7 @@ public class ExportTrackTaskTest extends ActivityInstrumentationTestCase2 - + + @@ -11,18 +12,18 @@ - + - - - - - + + + + + @@ -30,21 +31,21 @@ - - - + + + - + - + - - + diff --git a/app/src/main/java/org/osmtracker/OSMTracker.java b/app/src/main/java/net/osmtracker/OSMTracker.java similarity index 98% rename from app/src/main/java/org/osmtracker/OSMTracker.java rename to app/src/main/java/net/osmtracker/OSMTracker.java index 0333fd03..23cb1caa 100644 --- a/app/src/main/java/org/osmtracker/OSMTracker.java +++ b/app/src/main/java/net/osmtracker/OSMTracker.java @@ -1,4 +1,4 @@ -package org.osmtracker; +package net.osmtracker; /** @@ -44,7 +44,7 @@ public static final class Preferences { // Default values public final static String VAL_STORAGE_DIR = "/osmtracker"; public final static String VAL_VOICEREC_DURATION = "2"; - public final static String VAL_UI_THEME = "org.osmtracker:style/DefaultTheme"; + public final static String VAL_UI_THEME = "net.osmtracker:style/DefaultTheme"; public final static boolean VAL_GPS_CHECKSTARTUP = true; public final static boolean VAL_GPS_IGNORE_CLOCK = false; public final static String VAL_GPS_LOGGING_INTERVAL = "0"; diff --git a/app/src/main/java/org/osmtracker/activity/About.java b/app/src/main/java/net/osmtracker/activity/About.java similarity index 95% rename from app/src/main/java/org/osmtracker/activity/About.java rename to app/src/main/java/net/osmtracker/activity/About.java index df0ce4cf..2a5788ff 100644 --- a/app/src/main/java/org/osmtracker/activity/About.java +++ b/app/src/main/java/net/osmtracker/activity/About.java @@ -1,9 +1,9 @@ -package org.osmtracker.activity; +package net.osmtracker.activity; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.db.DatabaseHelper; -import org.osmtracker.db.ExportDatabaseTask; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.db.DatabaseHelper; +import net.osmtracker.db.ExportDatabaseTask; import android.app.Activity; import android.app.AlertDialog; diff --git a/app/src/main/java/org/osmtracker/activity/DisplayTrack.java b/app/src/main/java/net/osmtracker/activity/DisplayTrack.java similarity index 84% rename from app/src/main/java/org/osmtracker/activity/DisplayTrack.java rename to app/src/main/java/net/osmtracker/activity/DisplayTrack.java index 407418bf..9d1ab35d 100644 --- a/app/src/main/java/org/osmtracker/activity/DisplayTrack.java +++ b/app/src/main/java/net/osmtracker/activity/DisplayTrack.java @@ -1,9 +1,9 @@ -package org.osmtracker.activity; +package net.osmtracker.activity; -import org.osmtracker.OSMTracker; -import org.osmtracker.util.ThemeValidator; -import org.osmtracker.view.DisplayTrackView; -import org.osmtracker.db.TrackContentProvider; +import net.osmtracker.OSMTracker; +import net.osmtracker.util.ThemeValidator; +import net.osmtracker.view.DisplayTrackView; +import net.osmtracker.db.TrackContentProvider; import android.app.Activity; import android.app.AlertDialog; @@ -53,10 +53,10 @@ protected void onCreate(Bundle savedInstanceState) { @Override public void run() { new AlertDialog.Builder(DisplayTrack.this) - .setTitle(org.osmtracker.R.string.prefs_displaytrack_osm) - .setMessage(org.osmtracker.R.string.prefs_displaytrack_osm_summary_ask) + .setTitle(net.osmtracker.R.string.prefs_displaytrack_osm) + .setMessage(net.osmtracker.R.string.prefs_displaytrack_osm_summary_ask) .setNegativeButton(android.R.string.no, null) - .setPositiveButton(org.osmtracker.R.string.displaytrack_map, new DialogInterface.OnClickListener() { + .setPositiveButton(net.osmtracker.R.string.displaytrack_map, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { PreferenceManager.getDefaultSharedPreferences(DisplayTrack.this).edit() diff --git a/app/src/main/java/org/osmtracker/activity/DisplayTrackMap.java b/app/src/main/java/net/osmtracker/activity/DisplayTrackMap.java similarity index 98% rename from app/src/main/java/org/osmtracker/activity/DisplayTrackMap.java rename to app/src/main/java/net/osmtracker/activity/DisplayTrackMap.java index 9f142a06..ca12c120 100644 --- a/app/src/main/java/org/osmtracker/activity/DisplayTrackMap.java +++ b/app/src/main/java/net/osmtracker/activity/DisplayTrackMap.java @@ -1,13 +1,13 @@ -package org.osmtracker.activity; +package net.osmtracker.activity; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.db.TrackContentProvider; -import org.osmtracker.overlay.WayPointsOverlay; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.db.TrackContentProvider; +import net.osmtracker.overlay.WayPointsOverlay; import org.osmdroid.api.IMapController; import org.osmdroid.tileprovider.tilesource.ITileSource; diff --git a/app/src/main/java/org/osmtracker/activity/OpenStreetMapUpload.java b/app/src/main/java/net/osmtracker/activity/OpenStreetMapUpload.java similarity index 92% rename from app/src/main/java/org/osmtracker/activity/OpenStreetMapUpload.java rename to app/src/main/java/net/osmtracker/activity/OpenStreetMapUpload.java index 3ef18ea5..0c8b4de9 100644 --- a/app/src/main/java/org/osmtracker/activity/OpenStreetMapUpload.java +++ b/app/src/main/java/net/osmtracker/activity/OpenStreetMapUpload.java @@ -1,14 +1,14 @@ -package org.osmtracker.activity; +package net.osmtracker.activity; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.db.TrackContentProvider; -import org.osmtracker.db.model.Track; -import org.osmtracker.gpx.ExportToTempFileTask; -import org.osmtracker.osm.OpenStreetMapConstants; -import org.osmtracker.osm.RetrieveAccessTokenTask; -import org.osmtracker.osm.RetrieveRequestTokenTask; -import org.osmtracker.osm.UploadToOpenStreetMapTask; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.db.TrackContentProvider; +import net.osmtracker.db.model.Track; +import net.osmtracker.gpx.ExportToTempFileTask; +import net.osmtracker.osm.OpenStreetMapConstants; +import net.osmtracker.osm.RetrieveAccessTokenTask; +import net.osmtracker.osm.RetrieveRequestTokenTask; +import net.osmtracker.osm.UploadToOpenStreetMapTask; import oauth.signpost.OAuth; import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer; diff --git a/app/src/main/java/org/osmtracker/activity/Preferences.java b/app/src/main/java/net/osmtracker/activity/Preferences.java similarity index 80% rename from app/src/main/java/org/osmtracker/activity/Preferences.java rename to app/src/main/java/net/osmtracker/activity/Preferences.java index f9254b9e..be1e8142 100644 --- a/app/src/main/java/org/osmtracker/activity/Preferences.java +++ b/app/src/main/java/net/osmtracker/activity/Preferences.java @@ -1,13 +1,16 @@ -package org.osmtracker.activity; +package net.osmtracker.activity; import java.io.File; import java.io.FilenameFilter; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; + +import android.Manifest; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; +import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Environment; import android.preference.EditTextPreference; @@ -18,6 +21,9 @@ import android.preference.PreferenceActivity; import android.preference.PreferenceManager; import android.provider.Settings; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.util.Log; /** * Manages preferences screen. @@ -29,6 +35,8 @@ public class Preferences extends PreferenceActivity { @SuppressWarnings("unused") private static final String TAG = Preferences.class.getSimpleName(); + + final private int RC_READ_PERMISSION = 1; /** * Directory containing user layouts, relative to storage dir. @@ -64,14 +72,38 @@ public boolean onPreferenceChange(Preference preference, Object newValue) { preference.setSummary((String) newValue); // Re-populate layout list preference - populateLayoutPreference((String) newValue); + populateLayoutPreference((String) newValue); // Set layout to default layout ((ListPreference) findPreference(OSMTracker.Preferences.KEY_UI_BUTTONS_LAYOUT)).setValue(OSMTracker.Preferences.VAL_UI_BUTTONS_LAYOUT); return true; } }); - populateLayoutPreference(storageDirPref.getText()); + + if (ContextCompat.checkSelfPermission(this, + Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + + // Should we show an explanation? + if (ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.READ_EXTERNAL_STORAGE)) { + + // Show an explanation to the user *asynchronously* -- don't block + // this thread waiting for the user's response! After the user + // sees the explanation, try again to request the permission. + // TODO: explain why we need permission. + Log.w(TAG, "we should explain why we need read permission"); + + } else { + + // No explanation needed, we can request the permission. + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, RC_READ_PERMISSION); + } + + } else { + populateLayoutPreference(storageDirPref.getText()); + } + // Voice record duration Preference pref = findPreference(OSMTracker.Preferences.KEY_VOICEREC_DURATION); @@ -197,5 +229,28 @@ public boolean accept(File dir, String filename) { lf.setEntries(entries); lf.setEntryValues(values); } + + public void onRequestPermissionsResult(int requestCode, + String permissions[], int[] grantResults) { + switch (requestCode) { + case RC_READ_PERMISSION: { + // If request is cancelled, the result arrays are empty. + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + + // permission was granted, yay! + EditTextPreference storageDirPref = (EditTextPreference) findPreference(OSMTracker.Preferences.KEY_STORAGE_DIR); + populateLayoutPreference(storageDirPref.getText()); + + } else { + + // permission denied, boo! Disable the + // functionality that depends on this permission. + //TODO: add an informative message. + Log.w(TAG, "we should explain why we need read permission"); + } + } + } + } } diff --git a/app/src/main/java/org/osmtracker/activity/TrackDetail.java b/app/src/main/java/net/osmtracker/activity/TrackDetail.java similarity index 79% rename from app/src/main/java/org/osmtracker/activity/TrackDetail.java rename to app/src/main/java/net/osmtracker/activity/TrackDetail.java index 604e2041..4c98ed01 100644 --- a/app/src/main/java/org/osmtracker/activity/TrackDetail.java +++ b/app/src/main/java/net/osmtracker/activity/TrackDetail.java @@ -1,4 +1,4 @@ -package org.osmtracker.activity; +package net.osmtracker.activity; import java.sql.Date; import java.text.DateFormat; @@ -7,20 +7,25 @@ import java.util.List; import java.util.Map; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.db.TrackContentProvider; -import org.osmtracker.db.model.Track; -import org.osmtracker.gpx.ExportToStorageTask; -import org.osmtracker.util.MercatorProjection; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.db.TrackContentProvider; +import net.osmtracker.db.model.Track; +import net.osmtracker.gpx.ExportToStorageTask; +import net.osmtracker.util.MercatorProjection; +import android.Manifest; import android.content.ContentResolver; import android.content.ContentUris; import android.content.Intent; +import android.content.pm.PackageManager; import android.database.Cursor; import android.graphics.Paint; import android.os.Bundle; import android.preference.PreferenceManager; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -48,6 +53,8 @@ public class TrackDetail extends TrackDetailEditor implements AdapterView.OnItem @SuppressWarnings("unused") private static final String TAG = TrackDetail.class.getSimpleName(); + final private int RC_WRITE_PERMISSIONS = 1; + /** * Key to bind the "key" of each item using SimpleListAdapter */ @@ -230,14 +237,32 @@ public boolean onOptionsItemSelected(MenuItem item) { 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 data = (Map) adapter.getItem(adapter.getCount()-1); - data.put(ITEM_VALUE, DateFormat.getDateTimeInstance().format(new Date(System.currentTimeMillis()))); - adapter.notifyDataSetChanged(); - break; + if (ContextCompat.checkSelfPermission(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + + // Should we show an explanation? + if (ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + + // Show an expanation to the user *asynchronously* -- don't block + // this thread waiting for the user's response! After the user + // sees the explanation, try again to request the permission. + // TODO: explain why we need permission. + Log.w(TAG, "we should explain why we need write permission"); + + } else { + + // No explanation needed, we can request the permission. + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + RC_WRITE_PERMISSIONS); + break; + } + + } else { + exportTrack(); + break; + } case R.id.trackdetail_menu_osm_upload: i = new Intent(this, OpenStreetMapUpload.class); i.putExtra(TrackContentProvider.Schema.COL_TRACK_ID, trackId); @@ -246,6 +271,43 @@ public boolean onOptionsItemSelected(MenuItem item) { } return super.onOptionsItemSelected(item); } + + + /** + * Invoke the export track task after external write permissions request. + * + */ + private void exportTrack(){ + new ExportToStorageTask(this, trackId).execute(); + // Pick last list item (Exported date) and update it + SimpleAdapter adapter = ((SimpleAdapter) lv.getAdapter()); + @SuppressWarnings("unchecked") + Map data = (Map) adapter.getItem(adapter.getCount() - 1); + data.put(ITEM_VALUE, DateFormat.getDateTimeInstance().format(new Date(System.currentTimeMillis()))); + adapter.notifyDataSetChanged(); + } + + public void onRequestPermissionsResult(int requestCode, + String permissions[], int[] grantResults) { + switch (requestCode) { + case RC_WRITE_PERMISSIONS: { + // If request is cancelled, the result arrays are empty. + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + + // permission was granted, yay! + exportTrack(); + + } else { + + // permission denied, boo! Disable the + // functionality that depends on this permission. + //TODO: add an informative message. + } + return; + } + } + } /** * Handle clicks on list items; for Waypoint count, show this track's list of waypoints ({@link WaypointList}). diff --git a/app/src/main/java/org/osmtracker/activity/TrackDetailEditor.java b/app/src/main/java/net/osmtracker/activity/TrackDetailEditor.java similarity index 95% rename from app/src/main/java/org/osmtracker/activity/TrackDetailEditor.java rename to app/src/main/java/net/osmtracker/activity/TrackDetailEditor.java index aed273b2..98b430c3 100644 --- a/app/src/main/java/org/osmtracker/activity/TrackDetailEditor.java +++ b/app/src/main/java/net/osmtracker/activity/TrackDetailEditor.java @@ -1,8 +1,8 @@ -package org.osmtracker.activity; +package net.osmtracker.activity; -import org.osmtracker.R; -import org.osmtracker.db.TrackContentProvider; -import org.osmtracker.db.model.Track; +import net.osmtracker.R; +import net.osmtracker.db.TrackContentProvider; +import net.osmtracker.db.model.Track; import android.app.Activity; import android.content.ContentUris; diff --git a/app/src/main/java/org/osmtracker/activity/TrackLogger.java b/app/src/main/java/net/osmtracker/activity/TrackLogger.java similarity index 81% rename from app/src/main/java/org/osmtracker/activity/TrackLogger.java rename to app/src/main/java/net/osmtracker/activity/TrackLogger.java index 8c23d224..e4cb2384 100644 --- a/app/src/main/java/org/osmtracker/activity/TrackLogger.java +++ b/app/src/main/java/net/osmtracker/activity/TrackLogger.java @@ -1,23 +1,24 @@ -package org.osmtracker.activity; +package net.osmtracker.activity; import java.io.File; import java.util.Date; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.db.DataHelper; -import org.osmtracker.layout.GpsStatusRecord; -import org.osmtracker.layout.UserDefinedLayout; -import org.osmtracker.listener.SensorListener; -import org.osmtracker.receiver.MediaButtonReceiver; -import org.osmtracker.service.gps.GPSLogger; -import org.osmtracker.service.gps.GPSLoggerServiceConnection; -import org.osmtracker.util.FileSystemUtils; -import org.osmtracker.util.ThemeValidator; -import org.osmtracker.view.TextNoteDialog; -import org.osmtracker.view.VoiceRecDialog; -import org.osmtracker.db.TrackContentProvider; - +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.db.DataHelper; +import net.osmtracker.layout.GpsStatusRecord; +import net.osmtracker.layout.UserDefinedLayout; +import net.osmtracker.listener.SensorListener; +import net.osmtracker.receiver.MediaButtonReceiver; +import net.osmtracker.service.gps.GPSLogger; +import net.osmtracker.service.gps.GPSLoggerServiceConnection; +import net.osmtracker.util.FileSystemUtils; +import net.osmtracker.util.ThemeValidator; +import net.osmtracker.view.TextNoteDialog; +import net.osmtracker.view.VoiceRecDialog; +import net.osmtracker.db.TrackContentProvider; + +import android.Manifest; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; @@ -28,16 +29,20 @@ import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; import android.database.Cursor; import android.location.LocationManager; import android.media.AudioManager; import android.net.Uri; import android.os.Bundle; import android.os.Environment; +import android.os.StrictMode; import android.preference.PreferenceManager; import android.provider.MediaStore; import android.provider.MediaStore.Images.ImageColumns; import android.provider.Settings; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; @@ -59,6 +64,9 @@ public class TrackLogger extends Activity { private static final String TAG = TrackLogger.class.getSimpleName(); + final private int RC_STORAGE_AUDIO_PERMISSIONS = 1; + final private int RC_STORAGE_CAMERA_PERMISSIONS = 2; + /** * Request code for callback after the camera application had taken a * picture for us. @@ -418,8 +426,38 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { break; case KeyEvent.KEYCODE_CAMERA: if (gpsLogger.isTracking()) { - requestStillImage(); - return true; + if (ContextCompat.checkSelfPermission(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE) + ContextCompat.checkSelfPermission(this, + Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + + // Should we show an explanation? + if ( (ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE)) + || (ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.CAMERA)) ) { + + // Show an expanation to the user *asynchronously* -- don't block + // this thread waiting for the user's response! After the user + // sees the explanation, try again to request the permission. + // TODO: explain why we need permission. + Log.w(TAG, "we should explain why we need write and record audio permission"); + + } else { + + // No explanation needed, we can request the permission. + ActivityCompat.requestPermissions(this, + new String[]{ + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.CAMERA}, + RC_STORAGE_CAMERA_PERMISSIONS); + break; + } + + } else { + requestStillImage(); + //return true; + } + } break; case KeyEvent.KEYCODE_DPAD_CENTER: @@ -597,8 +635,37 @@ protected Dialog onCreateDialog(int id) { // create a new TextNoteDialog return new TextNoteDialog(this, currentTrackId); case DIALOG_VOICE_RECORDING: - // create a new VoiceRegDialog - return new VoiceRecDialog(this, currentTrackId); + if (ContextCompat.checkSelfPermission(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE) + ContextCompat.checkSelfPermission(this, + Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { + + // Should we show an explanation? + if ( (ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE)) + || (ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.RECORD_AUDIO)) ) { + + // Show an expanation to the user *asynchronously* -- don't block + // this thread waiting for the user's response! After the user + // sees the explanation, try again to request the permission. + // TODO: explain why we need permission. + Log.w(TAG, "we should explain why we need write and record audio permission"); + + } else { + + // No explanation needed, we can request the permission. + ActivityCompat.requestPermissions(this, + new String[]{ + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.RECORD_AUDIO}, + RC_STORAGE_AUDIO_PERMISSIONS); + break; + } + + } else { + // create a new VoiceRegDialog + return new VoiceRecDialog(this, currentTrackId); + } } return super.onCreateDialog(id); } @@ -638,6 +705,8 @@ public long getCurrentTrackId() { * @param imageFile File to save the picture to */ private void startCamera(File imageFile) { + StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); + StrictMode.setVmPolicy(builder.build()); Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(imageFile)); startActivityForResult(cameraIntent, REQCODE_IMAGE_CAPTURE); @@ -652,6 +721,47 @@ private void startGallery() { intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult(Intent.createChooser(intent, getString(R.string.tracklogger_choose_gallery_camera)), REQCODE_GALLERY_CHOSEN); } - + + public void onRequestPermissionsResult(int requestCode, + String permissions[], int[] grantResults) { + switch (requestCode) { + case RC_STORAGE_AUDIO_PERMISSIONS: { + // If request is cancelled, the result arrays are empty. + if (grantResults.length == 2 + && grantResults[0] == PackageManager.PERMISSION_GRANTED + && grantResults[1] == PackageManager.PERMISSION_GRANTED) { + + // permission was granted, yay! + new VoiceRecDialog(this, currentTrackId); + + } else { + + // permission denied, boo! Disable the + // functionality that depends on this permission. + //TODO: add an informative message. + } + return; + } + + case RC_STORAGE_CAMERA_PERMISSIONS: { + // If request is cancelled, the result arrays are empty. + if (grantResults.length == 2 + && grantResults[0] == PackageManager.PERMISSION_GRANTED + && grantResults[1] == PackageManager.PERMISSION_GRANTED) { + + // permission was granted, yay! + requestStillImage(); + + } else { + + // permission denied, boo! Disable the + // functionality that depends on this permission. + //TODO: add an informative message. + } + return; + } + } + } + } diff --git a/app/src/main/java/org/osmtracker/activity/TrackManager.java b/app/src/main/java/net/osmtracker/activity/TrackManager.java similarity index 76% rename from app/src/main/java/org/osmtracker/activity/TrackManager.java rename to app/src/main/java/net/osmtracker/activity/TrackManager.java index a0f13de7..10d822e8 100644 --- a/app/src/main/java/org/osmtracker/activity/TrackManager.java +++ b/app/src/main/java/net/osmtracker/activity/TrackManager.java @@ -1,17 +1,18 @@ -package org.osmtracker.activity; +package net.osmtracker.activity; import java.io.File; import java.util.Date; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.db.DataHelper; -import org.osmtracker.db.TrackContentProvider; -import org.osmtracker.db.TracklistAdapter; -import org.osmtracker.exception.CreateTrackException; -import org.osmtracker.gpx.ExportToStorageTask; -import org.osmtracker.util.FileSystemUtils; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.db.DataHelper; +import net.osmtracker.db.TrackContentProvider; +import net.osmtracker.db.TracklistAdapter; +import net.osmtracker.exception.CreateTrackException; +import net.osmtracker.gpx.ExportToStorageTask; +import net.osmtracker.util.FileSystemUtils; +import android.Manifest; import android.app.AlertDialog; import android.app.ListActivity; import android.content.ContentUris; @@ -19,10 +20,14 @@ import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; +import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceManager; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; @@ -46,6 +51,9 @@ public class TrackManager extends ListActivity { @SuppressWarnings("unused") private static final String TAG = TrackManager.class.getSimpleName(); + final private int RC_WRITE_PERMISSIONS_EXPORT_ALL = 1; + final private int RC_WRITE_PERMISSIONS_EXPORT_ONE = 2; + /** Bundle key for {@link #prevItemVisible} */ private static final String PREV_VISIBLE = "prev_visible"; @@ -58,6 +66,9 @@ public class TrackManager extends ListActivity { /** The previous item visible, or -1; for scrolling back to its position in {@link #onResume()} */ private int prevItemVisible = -1; + /** Track Identifier to export after request for write permission **/ + private long trackId = -1; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -232,19 +243,7 @@ public void onClick(DialogInterface dialog, int which) { .setPositiveButton(R.string.menu_exportall, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - Cursor cursor = getContentResolver().query(TrackContentProvider.CONTENT_URI_TRACK, - null, null, null, TrackContentProvider.Schema.COL_START_DATE + " desc"); - if (cursor.moveToFirst()) { - long[] ids = new long[cursor.getCount()]; - int idCol = cursor.getColumnIndex(TrackContentProvider.Schema.COL_ID); - int i=0; - do { - ids[i++] = cursor.getLong(idCol); - } while (cursor.moveToNext()); - - new ExportToStorageTask(TrackManager.this, ids).execute(); - } - cursor.close(); + requestPermissionAndExport(TrackManager.this.RC_WRITE_PERMISSIONS_EXPORT_ALL); } }) .setNegativeButton(android.R.string.cancel, new OnClickListener() { @@ -266,6 +265,63 @@ public void onClick(DialogInterface dialog, int which) { return super.onOptionsItemSelected(item); } + + private void requestPermissionAndExport(int typeCode){ + if (ContextCompat.checkSelfPermission(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + + // Should we show an explanation? + if (ActivityCompat.shouldShowRequestPermissionRationale(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + + // Show an explanation to the user *asynchronously* -- don't block + // this thread waiting for the user's response! After the user + // sees the explanation, try again to request the permission. + // TODO: explain why we need permission. + Log.w(TAG, "we should explain why we need write permission_REQUEST"); + Toast.makeText(this, "To export the GPX trace we need to write on the storage.", Toast.LENGTH_LONG).show(); + + } else { + + // No explanation needed, we can request the permission. + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, typeCode); + } + + } else { + switch (typeCode) { + case RC_WRITE_PERMISSIONS_EXPORT_ALL: + exportAllTracks(); + + case RC_WRITE_PERMISSIONS_EXPORT_ONE: + exportOneTrack(); + } + } + } + + private void exportOneTrack(){ + if (trackId != -1) { + new ExportToStorageTask(this, trackId).execute(); + trackId = -1; + } + } + + private void exportAllTracks(){ + Cursor cursor = getContentResolver().query(TrackContentProvider.CONTENT_URI_TRACK, + null, null, null, TrackContentProvider.Schema.COL_START_DATE + " desc"); + if (cursor.moveToFirst()) { + long[] ids = new long[cursor.getCount()]; + int idCol = cursor.getColumnIndex(TrackContentProvider.Schema.COL_ID); + int i=0; + do { + ids[i++] = cursor.getLong(idCol); + } while (cursor.moveToNext()); + + new ExportToStorageTask(TrackManager.this, ids).execute(); + } + cursor.close(); + } + @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); @@ -328,8 +384,9 @@ public void onClick(DialogInterface dialog, int which) { }).create().show(); break; - case R.id.trackmgr_contextmenu_export: - new ExportToStorageTask(this, info.id).execute(); + case R.id.trackmgr_contextmenu_export: + trackId = info.id; + requestPermissionAndExport(this.RC_WRITE_PERMISSIONS_EXPORT_ONE); break; case R.id.trackmgr_contextmenu_osm_upload: i = new Intent(this, OpenStreetMapUpload.class); @@ -475,5 +532,46 @@ private void stopActiveTrack(){ } } - + + public void onRequestPermissionsResult(int requestCode, + String permissions[], int[] grantResults) { + switch (requestCode) { + case RC_WRITE_PERMISSIONS_EXPORT_ALL: { + // If request is cancelled, the result arrays are empty. + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + + // permission was granted, yay! + exportAllTracks(); + + } else { + + // permission denied, boo! Disable the + // functionality that depends on this permission. + //TODO: add an informative message. + Log.w(TAG, "we should explain why we need write permission_EXPORT_ALL"); + Toast.makeText(this, "To export the GPX trace we need to write on the storage.", Toast.LENGTH_LONG).show(); + } + } + case RC_WRITE_PERMISSIONS_EXPORT_ONE: { + // If request is cancelled, the result arrays are empty. + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + + // permission was granted, yay! + exportOneTrack(); + + } else { + + // permission denied, boo! Disable the + // functionality that depends on this permission. + //TODO: add an informative message. + Log.w(TAG, "we should explain why we need write permission_EXPORT_ONE"); + Toast.makeText(this, "To export the GPX trace we need to write on the storage.", Toast.LENGTH_LONG).show(); + } + } + } + } + + } diff --git a/app/src/main/java/org/osmtracker/activity/WaypointList.java b/app/src/main/java/net/osmtracker/activity/WaypointList.java similarity index 88% rename from app/src/main/java/org/osmtracker/activity/WaypointList.java rename to app/src/main/java/net/osmtracker/activity/WaypointList.java index d78960f7..f337e7c5 100644 --- a/app/src/main/java/org/osmtracker/activity/WaypointList.java +++ b/app/src/main/java/net/osmtracker/activity/WaypointList.java @@ -1,7 +1,7 @@ -package org.osmtracker.activity; +package net.osmtracker.activity; -import org.osmtracker.db.TrackContentProvider; -import org.osmtracker.db.WaypointListAdapter; +import net.osmtracker.db.TrackContentProvider; +import net.osmtracker.db.WaypointListAdapter; import android.app.ListActivity; import android.database.Cursor; diff --git a/app/src/main/java/org/osmtracker/db/DataHelper.java b/app/src/main/java/net/osmtracker/db/DataHelper.java similarity index 99% rename from app/src/main/java/org/osmtracker/db/DataHelper.java rename to app/src/main/java/net/osmtracker/db/DataHelper.java index 83a660a3..5e0868b0 100644 --- a/app/src/main/java/org/osmtracker/db/DataHelper.java +++ b/app/src/main/java/net/osmtracker/db/DataHelper.java @@ -1,9 +1,9 @@ -package org.osmtracker.db; +package net.osmtracker.db; import java.io.File; import java.text.SimpleDateFormat; -import org.osmtracker.OSMTracker; +import net.osmtracker.OSMTracker; import android.content.ContentResolver; import android.content.ContentUris; diff --git a/app/src/main/java/org/osmtracker/db/DatabaseHelper.java b/app/src/main/java/net/osmtracker/db/DatabaseHelper.java similarity index 96% rename from app/src/main/java/org/osmtracker/db/DatabaseHelper.java rename to app/src/main/java/net/osmtracker/db/DatabaseHelper.java index 6f766dc3..94703c98 100644 --- a/app/src/main/java/org/osmtracker/db/DatabaseHelper.java +++ b/app/src/main/java/net/osmtracker/db/DatabaseHelper.java @@ -1,10 +1,10 @@ -package org.osmtracker.db; +package net.osmtracker.db; import java.io.File; import java.io.FilenameFilter; -import org.osmtracker.OSMTracker; -import org.osmtracker.util.FileSystemUtils; +import net.osmtracker.OSMTracker; +import net.osmtracker.util.FileSystemUtils; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; @@ -12,7 +12,7 @@ import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; -import org.osmtracker.db.model.Track; +import net.osmtracker.db.model.Track; /** * Helper for managing database. diff --git a/app/src/main/java/org/osmtracker/db/ExportDatabaseTask.java b/app/src/main/java/net/osmtracker/db/ExportDatabaseTask.java similarity index 97% rename from app/src/main/java/org/osmtracker/db/ExportDatabaseTask.java rename to app/src/main/java/net/osmtracker/db/ExportDatabaseTask.java index b4e18a32..d6193438 100644 --- a/app/src/main/java/org/osmtracker/db/ExportDatabaseTask.java +++ b/app/src/main/java/net/osmtracker/db/ExportDatabaseTask.java @@ -1,4 +1,4 @@ -package org.osmtracker.db; +package net.osmtracker.db; import android.os.AsyncTask; import android.os.Bundle; @@ -11,7 +11,7 @@ import java.io.OutputStream; import java.util.zip.GZIPOutputStream; -import org.osmtracker.activity.About; +import net.osmtracker.activity.About; /** * Task to export the internal database to the external storage, diff --git a/app/src/main/java/org/osmtracker/db/TrackContentProvider.java b/app/src/main/java/net/osmtracker/db/TrackContentProvider.java similarity index 99% rename from app/src/main/java/org/osmtracker/db/TrackContentProvider.java rename to app/src/main/java/net/osmtracker/db/TrackContentProvider.java index 3325fc74..652f85ac 100644 --- a/app/src/main/java/org/osmtracker/db/TrackContentProvider.java +++ b/app/src/main/java/net/osmtracker/db/TrackContentProvider.java @@ -1,9 +1,9 @@ -package org.osmtracker.db; +package net.osmtracker.db; import java.util.ArrayList; import java.util.List; -import org.osmtracker.OSMTracker; +import net.osmtracker.OSMTracker; import android.content.ContentProvider; import android.content.ContentResolver; diff --git a/app/src/main/java/org/osmtracker/db/TracklistAdapter.java b/app/src/main/java/net/osmtracker/db/TracklistAdapter.java similarity index 92% rename from app/src/main/java/org/osmtracker/db/TracklistAdapter.java rename to app/src/main/java/net/osmtracker/db/TracklistAdapter.java index ca2d5452..b3b0f3d1 100644 --- a/app/src/main/java/org/osmtracker/db/TracklistAdapter.java +++ b/app/src/main/java/net/osmtracker/db/TracklistAdapter.java @@ -1,8 +1,8 @@ -package org.osmtracker.db; +package net.osmtracker.db; -import org.osmtracker.R; -import org.osmtracker.db.model.Track; -import org.osmtracker.activity.TrackManager; +import net.osmtracker.R; +import net.osmtracker.db.model.Track; +import net.osmtracker.activity.TrackManager; import android.content.Context; import android.database.Cursor; diff --git a/app/src/main/java/org/osmtracker/db/WaypointListAdapter.java b/app/src/main/java/net/osmtracker/db/WaypointListAdapter.java similarity index 98% rename from app/src/main/java/org/osmtracker/db/WaypointListAdapter.java rename to app/src/main/java/net/osmtracker/db/WaypointListAdapter.java index 1cc22ed7..b8f847a4 100644 --- a/app/src/main/java/org/osmtracker/db/WaypointListAdapter.java +++ b/app/src/main/java/net/osmtracker/db/WaypointListAdapter.java @@ -1,10 +1,10 @@ -package org.osmtracker.db; +package net.osmtracker.db; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; -import org.osmtracker.R; +import net.osmtracker.R; import android.content.Context; import android.database.Cursor; diff --git a/app/src/main/java/org/osmtracker/db/model/Track.java b/app/src/main/java/net/osmtracker/db/model/Track.java similarity index 98% rename from app/src/main/java/org/osmtracker/db/model/Track.java rename to app/src/main/java/net/osmtracker/db/model/Track.java index 0a2d2a8c..0cf7c227 100644 --- a/app/src/main/java/org/osmtracker/db/model/Track.java +++ b/app/src/main/java/net/osmtracker/db/model/Track.java @@ -1,4 +1,4 @@ -package org.osmtracker.db.model; +package net.osmtracker.db.model; import java.text.DateFormat; import java.util.ArrayList; @@ -6,8 +6,8 @@ import java.util.Date; import java.util.List; -import org.osmtracker.R; -import org.osmtracker.db.TrackContentProvider; +import net.osmtracker.R; +import net.osmtracker.db.TrackContentProvider; import android.content.ContentResolver; import android.database.Cursor; diff --git a/app/src/main/java/org/osmtracker/exception/CreateTrackException.java b/app/src/main/java/net/osmtracker/exception/CreateTrackException.java similarity index 79% rename from app/src/main/java/org/osmtracker/exception/CreateTrackException.java rename to app/src/main/java/net/osmtracker/exception/CreateTrackException.java index 95379b0e..b9e3c955 100644 --- a/app/src/main/java/org/osmtracker/exception/CreateTrackException.java +++ b/app/src/main/java/net/osmtracker/exception/CreateTrackException.java @@ -1,4 +1,4 @@ -package org.osmtracker.exception; +package net.osmtracker.exception; public class CreateTrackException extends Exception { diff --git a/app/src/main/java/org/osmtracker/exception/ExportTrackException.java b/app/src/main/java/net/osmtracker/exception/ExportTrackException.java similarity index 79% rename from app/src/main/java/org/osmtracker/exception/ExportTrackException.java rename to app/src/main/java/net/osmtracker/exception/ExportTrackException.java index 17c2471d..1296cbac 100644 --- a/app/src/main/java/org/osmtracker/exception/ExportTrackException.java +++ b/app/src/main/java/net/osmtracker/exception/ExportTrackException.java @@ -1,4 +1,4 @@ -package org.osmtracker.exception; +package net.osmtracker.exception; public class ExportTrackException extends Exception { diff --git a/app/src/main/java/org/osmtracker/gpx/ExportToStorageTask.java b/app/src/main/java/net/osmtracker/gpx/ExportToStorageTask.java similarity index 94% rename from app/src/main/java/org/osmtracker/gpx/ExportToStorageTask.java rename to app/src/main/java/net/osmtracker/gpx/ExportToStorageTask.java index a5427b60..e086e783 100644 --- a/app/src/main/java/org/osmtracker/gpx/ExportToStorageTask.java +++ b/app/src/main/java/net/osmtracker/gpx/ExportToStorageTask.java @@ -1,12 +1,12 @@ -package org.osmtracker.gpx; +package net.osmtracker.gpx; import java.io.File; import java.util.Date; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.db.DataHelper; -import org.osmtracker.exception.ExportTrackException; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.db.DataHelper; +import net.osmtracker.exception.ExportTrackException; import android.content.Context; import android.content.SharedPreferences; diff --git a/app/src/main/java/org/osmtracker/gpx/ExportToTempFileTask.java b/app/src/main/java/net/osmtracker/gpx/ExportToTempFileTask.java similarity index 95% rename from app/src/main/java/org/osmtracker/gpx/ExportToTempFileTask.java rename to app/src/main/java/net/osmtracker/gpx/ExportToTempFileTask.java index 7133dc85..f9306d46 100644 --- a/app/src/main/java/org/osmtracker/gpx/ExportToTempFileTask.java +++ b/app/src/main/java/net/osmtracker/gpx/ExportToTempFileTask.java @@ -1,10 +1,10 @@ -package org.osmtracker.gpx; +package net.osmtracker.gpx; import java.io.File; import java.io.IOException; import java.util.Date; -import org.osmtracker.exception.ExportTrackException; +import net.osmtracker.exception.ExportTrackException; import android.content.Context; import android.database.Cursor; import android.util.Log; diff --git a/app/src/main/java/org/osmtracker/gpx/ExportTrackTask.java b/app/src/main/java/net/osmtracker/gpx/ExportTrackTask.java similarity index 85% rename from app/src/main/java/org/osmtracker/gpx/ExportTrackTask.java rename to app/src/main/java/net/osmtracker/gpx/ExportTrackTask.java index 0628a6b2..9d7a3cf7 100644 --- a/app/src/main/java/org/osmtracker/gpx/ExportTrackTask.java +++ b/app/src/main/java/net/osmtracker/gpx/ExportTrackTask.java @@ -1,4 +1,4 @@ -package org.osmtracker.gpx; +package net.osmtracker.gpx; import java.io.BufferedWriter; import java.io.File; @@ -12,12 +12,14 @@ import java.util.TimeZone; import java.util.regex.Pattern; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.db.DataHelper; -import org.osmtracker.db.TrackContentProvider; -import org.osmtracker.exception.ExportTrackException; -import org.osmtracker.util.FileSystemUtils; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.db.DataHelper; +import net.osmtracker.db.TrackContentProvider; +import net.osmtracker.exception.ExportTrackException; +import net.osmtracker.util.FileSystemUtils; + +import android.Manifest; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.ContentResolver; @@ -25,11 +27,13 @@ import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; +import android.content.pm.PackageManager; import android.database.Cursor; import android.media.MediaScannerConnection; import android.os.AsyncTask; import android.os.Environment; import android.preference.PreferenceManager; +import android.support.v4.content.ContextCompat; import android.util.Log; /** @@ -65,7 +69,7 @@ public abstract class ExportTrackTask extends AsyncTask { private static final String TAG_GPX = ""; @@ -189,69 +193,76 @@ public void onClick(DialogInterface dialog, int which) { } private void exportTrackAsGpx(long trackId) throws ExportTrackException { + + String state = Environment.getExternalStorageState(); File sdRoot = Environment.getExternalStorageDirectory(); - - if (sdRoot.canWrite()) { - ContentResolver cr = context.getContentResolver(); - - Cursor c = context.getContentResolver().query(ContentUris.withAppendedId( - TrackContentProvider.CONTENT_URI_TRACK, trackId), null, null, - null, null); - - // Get the startDate of this track - // TODO: Maybe we should be pulling the track name instead? - // We'd need to consider the possibility that two tracks were given the same name - // We could possibly disambiguate by including the track ID in the Folder Name - // to avoid overwriting another track on one hand or needlessly creating additional - // directories to avoid overwriting. - Date startDate = new Date(); - if (null != c && 1 <= c.getCount()) { - c.moveToFirst(); - long startDateInMilliseconds = c.getLong(c.getColumnIndex(TrackContentProvider.Schema.COL_START_DATE)); - startDate.setTime(startDateInMilliseconds); - } - File trackGPXExportDirectory = getExportDirectory(startDate); - String filenameBase = buildGPXFilename(c); - c.close(); - - File trackFile = new File(trackGPXExportDirectory, filenameBase); + if (ContextCompat.checkSelfPermission(context, + Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { - - Cursor cTrackPoints = cr.query(TrackContentProvider.trackPointsUri(trackId), null, - null, null, TrackContentProvider.Schema.COL_TIMESTAMP + " asc"); - Cursor cWayPoints = cr.query(TrackContentProvider.waypointsUri(trackId), null, null, - null, TrackContentProvider.Schema.COL_TIMESTAMP + " asc"); - - if (null != cTrackPoints && null != cWayPoints) { - publishProgress(new Long[] { trackId, (long) cTrackPoints.getCount(), (long) cWayPoints.getCount() }); - - try { - writeGpxFile(cTrackPoints, cWayPoints, trackFile); - if (exportMediaFiles()) { - copyWaypointFiles(trackId, trackGPXExportDirectory); + if (sdRoot.canWrite()) { + ContentResolver cr = context.getContentResolver(); + + Cursor c = context.getContentResolver().query(ContentUris.withAppendedId( + TrackContentProvider.CONTENT_URI_TRACK, trackId), null, null, + null, null); + + // Get the startDate of this track + // TODO: Maybe we should be pulling the track name instead? + // We'd need to consider the possibility that two tracks were given the same name + // We could possibly disambiguate by including the track ID in the Folder Name + // to avoid overwriting another track on one hand or needlessly creating additional + // directories to avoid overwriting. + Date startDate = new Date(); + if (null != c && 1 <= c.getCount()) { + c.moveToFirst(); + long startDateInMilliseconds = c.getLong(c.getColumnIndex(TrackContentProvider.Schema.COL_START_DATE)); + startDate.setTime(startDateInMilliseconds); + } + + File trackGPXExportDirectory = getExportDirectory(startDate); + String filenameBase = buildGPXFilename(c); + c.close(); + + File trackFile = new File(trackGPXExportDirectory, filenameBase); + + + Cursor cTrackPoints = cr.query(TrackContentProvider.trackPointsUri(trackId), null, + null, null, TrackContentProvider.Schema.COL_TIMESTAMP + " asc"); + Cursor cWayPoints = cr.query(TrackContentProvider.waypointsUri(trackId), null, null, + null, TrackContentProvider.Schema.COL_TIMESTAMP + " asc"); + + if (null != cTrackPoints && null != cWayPoints) { + publishProgress(new Long[]{trackId, (long) cTrackPoints.getCount(), (long) cWayPoints.getCount()}); + + try { + writeGpxFile(cTrackPoints, cWayPoints, trackFile); + if (exportMediaFiles()) { + copyWaypointFiles(trackId, trackGPXExportDirectory); + } + if (updateExportDate()) { + DataHelper.setTrackExportDate(trackId, System.currentTimeMillis(), cr); + } + } catch (IOException ioe) { + throw new ExportTrackException(ioe.getMessage()); + } finally { + cTrackPoints.close(); + cWayPoints.close(); } - if (updateExportDate()) { - DataHelper.setTrackExportDate(trackId, System.currentTimeMillis(), cr); + + // Force rescan of directory + ArrayList files = new ArrayList(); + for (File file : trackGPXExportDirectory.listFiles()) { + files.add(file.getAbsolutePath()); } - } catch (IOException ioe) { - throw new ExportTrackException(ioe.getMessage()); - } finally { - cTrackPoints.close(); - cWayPoints.close(); - } + MediaScannerConnection.scanFile(context, files.toArray(new String[0]), null, null); - // Force rescan of directory - ArrayList files = new ArrayList(); - for (File file: trackGPXExportDirectory.listFiles()) { - files.add(file.getAbsolutePath()); } - MediaScannerConnection.scanFile(context, files.toArray(new String[0]), null, null); - + } else { + throw new ExportTrackException(context.getResources().getString(R.string.error_externalstorage_not_writable)); } - } else { - throw new ExportTrackException(context.getResources().getString(R.string.error_externalstorage_not_writable)); } + } /** diff --git a/app/src/main/java/org/osmtracker/layout/DisablableTableLayout.java b/app/src/main/java/net/osmtracker/layout/DisablableTableLayout.java similarity index 97% rename from app/src/main/java/org/osmtracker/layout/DisablableTableLayout.java rename to app/src/main/java/net/osmtracker/layout/DisablableTableLayout.java index 6cd7c9b4..a4508277 100644 --- a/app/src/main/java/org/osmtracker/layout/DisablableTableLayout.java +++ b/app/src/main/java/net/osmtracker/layout/DisablableTableLayout.java @@ -1,4 +1,4 @@ -package org.osmtracker.layout; +package net.osmtracker.layout; import android.content.Context; import android.view.View; diff --git a/app/src/main/java/org/osmtracker/layout/GpsStatusRecord.java b/app/src/main/java/net/osmtracker/layout/GpsStatusRecord.java similarity index 84% rename from app/src/main/java/org/osmtracker/layout/GpsStatusRecord.java rename to app/src/main/java/net/osmtracker/layout/GpsStatusRecord.java index ae9956a6..372270da 100644 --- a/app/src/main/java/org/osmtracker/layout/GpsStatusRecord.java +++ b/app/src/main/java/net/osmtracker/layout/GpsStatusRecord.java @@ -1,11 +1,15 @@ -package org.osmtracker.layout; +package net.osmtracker.layout; import java.text.DecimalFormat; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.activity.TrackLogger; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.activity.TrackLogger; + +import android.Manifest; +import android.app.Activity; import android.content.Context; +import android.content.pm.PackageManager; import android.location.GpsSatellite; import android.location.GpsStatus; import android.location.GpsStatus.Listener; @@ -15,6 +19,9 @@ import android.location.LocationProvider; import android.os.Bundle; import android.preference.PreferenceManager; +import android.support.annotation.NonNull; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; @@ -32,7 +39,9 @@ public class GpsStatusRecord extends LinearLayout implements Listener, LocationListener { private final static String TAG = GpsStatusRecord.class.getSimpleName(); - + + final private int REQUEST_CODE_GPS_PERMISSIONS = 1; + /** * Formatter for accuracy display. */ @@ -108,8 +117,15 @@ public GpsStatusRecord(Context context, AttributeSet attrs) { public void requestLocationUpdates(boolean request) { if (request) { - lmgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); - lmgr.addGpsStatusListener(this); + + if (ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + lmgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); + lmgr.addGpsStatusListener(this); + } + else { + ActivityCompat.requestPermissions((Activity) activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, + REQUEST_CODE_GPS_PERMISSIONS); + } } else { lmgr.removeUpdates(this); lmgr.removeGpsStatusListener(this); @@ -138,6 +154,9 @@ public void onGpsStatusChanged(int event) { if((event != GpsStatus.GPS_EVENT_SATELLITE_STATUS) || (lastGPSTimestampStatus + gpsLoggingInterval) < System.currentTimeMillis()){ lastGPSTimestampStatus = System.currentTimeMillis(); // save the time of this fix + if (ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + break; + } GpsStatus status = lmgr.getGpsStatus(null); satCount = 0; @@ -175,6 +194,7 @@ public void onGpsStatusChanged(int event) { } } + @Override public void onLocationChanged(Location location) { // first of all we check if the time from the last used fix to the current fix is greater than the logging interval @@ -253,4 +273,17 @@ public void manageRecordingIndicator(boolean isTracking) { } } + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + switch (requestCode) { + case REQUEST_CODE_GPS_PERMISSIONS: + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + requestLocationUpdates(true); + // do something + return; + } else { + requestLocationUpdates(false); + } + } + } + } diff --git a/app/src/main/java/org/osmtracker/layout/UserDefinedLayout.java b/app/src/main/java/net/osmtracker/layout/UserDefinedLayout.java similarity index 88% rename from app/src/main/java/org/osmtracker/layout/UserDefinedLayout.java rename to app/src/main/java/net/osmtracker/layout/UserDefinedLayout.java index d4df5eb8..ec6f67f5 100644 --- a/app/src/main/java/org/osmtracker/layout/UserDefinedLayout.java +++ b/app/src/main/java/net/osmtracker/layout/UserDefinedLayout.java @@ -1,4 +1,4 @@ -package org.osmtracker.layout; +package net.osmtracker.layout; import java.io.File; import java.io.FileReader; @@ -6,12 +6,12 @@ import java.util.HashMap; import java.util.Stack; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.activity.TrackLogger; -import org.osmtracker.service.resources.AppResourceIconResolver; -import org.osmtracker.service.resources.ExternalDirectoryIconResolver; -import org.osmtracker.util.UserDefinedLayoutReader; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.activity.TrackLogger; +import net.osmtracker.service.resources.AppResourceIconResolver; +import net.osmtracker.service.resources.ExternalDirectoryIconResolver; +import net.osmtracker.util.UserDefinedLayoutReader; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; diff --git a/app/src/main/java/org/osmtracker/listener/PageButtonOnClickListener.java b/app/src/main/java/net/osmtracker/listener/PageButtonOnClickListener.java similarity index 85% rename from app/src/main/java/org/osmtracker/listener/PageButtonOnClickListener.java rename to app/src/main/java/net/osmtracker/listener/PageButtonOnClickListener.java index 76683ed9..50a785a2 100644 --- a/app/src/main/java/org/osmtracker/listener/PageButtonOnClickListener.java +++ b/app/src/main/java/net/osmtracker/listener/PageButtonOnClickListener.java @@ -1,6 +1,6 @@ -package org.osmtracker.listener; +package net.osmtracker.listener; -import org.osmtracker.layout.UserDefinedLayout; +import net.osmtracker.layout.UserDefinedLayout; import android.view.View; import android.view.View.OnClickListener; diff --git a/app/src/main/java/org/osmtracker/listener/SensorListener.java b/app/src/main/java/net/osmtracker/listener/SensorListener.java similarity index 98% rename from app/src/main/java/org/osmtracker/listener/SensorListener.java rename to app/src/main/java/net/osmtracker/listener/SensorListener.java index 01822555..467c6d10 100644 --- a/app/src/main/java/org/osmtracker/listener/SensorListener.java +++ b/app/src/main/java/net/osmtracker/listener/SensorListener.java @@ -1,9 +1,9 @@ -package org.osmtracker.listener; +package net.osmtracker.listener; import java.text.DecimalFormat; -import org.osmtracker.R; -import org.osmtracker.db.DataHelper; +import net.osmtracker.R; +import net.osmtracker.db.DataHelper; import android.app.Activity; import android.content.Context; import android.graphics.Color; diff --git a/app/src/main/java/net/osmtracker/listener/StillImageOnClickListener.java b/app/src/main/java/net/osmtracker/listener/StillImageOnClickListener.java new file mode 100644 index 00000000..99f51c6f --- /dev/null +++ b/app/src/main/java/net/osmtracker/listener/StillImageOnClickListener.java @@ -0,0 +1,90 @@ +package net.osmtracker.listener; + +import net.osmtracker.activity.TrackLogger; +import net.osmtracker.view.VoiceRecDialog; + +import android.Manifest; +import android.content.pm.PackageManager; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; + +/** + * Manages still image recording with camera app. + * + * @author Nicolas Guillaumin + * + */ +public class StillImageOnClickListener implements OnClickListener { + + /** + * Parent activity + */ + TrackLogger activity; + + final private int RC_STORAGE_CAMERA_PERMISSIONS = 2; + + public StillImageOnClickListener(TrackLogger parent) { + activity = parent; + } + + @Override + public void onClick(View v) { + if (ContextCompat.checkSelfPermission(activity, + Manifest.permission.WRITE_EXTERNAL_STORAGE) + ContextCompat.checkSelfPermission(activity, + Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + + // Should we show an explanation? + if ( (ActivityCompat.shouldShowRequestPermissionRationale(activity, + Manifest.permission.WRITE_EXTERNAL_STORAGE)) + || (ActivityCompat.shouldShowRequestPermissionRationale(activity, + Manifest.permission.CAMERA)) ) { + + // Show an expanation to the user *asynchronously* -- don't block + // this thread waiting for the user's response! After the user + // sees the explanation, try again to request the permission. + // TODO: explain why we need permission. + //"we should explain why we need write and record audio permission" + + } else { + + // No explanation needed, we can request the permission. + ActivityCompat.requestPermissions(activity, + new String[]{ + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.CAMERA}, + RC_STORAGE_CAMERA_PERMISSIONS); + } + + } else { + activity.requestStillImage(); + } + + } + + public void onRequestPermissionsResult(int requestCode, + String permissions[], int[] grantResults) { + switch (requestCode) { + case RC_STORAGE_CAMERA_PERMISSIONS: { + // If request is cancelled, the result arrays are empty. + if (grantResults.length == 2 + && grantResults[0] == PackageManager.PERMISSION_GRANTED + && grantResults[1] == PackageManager.PERMISSION_GRANTED) { + + // permission was granted, yay! + activity.requestStillImage(); + + } else { + + // permission denied, boo! Disable the + // functionality that depends on this permission. + //TODO: add an informative message. + } + return; + } + } + } + +} diff --git a/app/src/main/java/org/osmtracker/listener/TagButtonOnClickListener.java b/app/src/main/java/net/osmtracker/listener/TagButtonOnClickListener.java similarity index 86% rename from app/src/main/java/org/osmtracker/listener/TagButtonOnClickListener.java rename to app/src/main/java/net/osmtracker/listener/TagButtonOnClickListener.java index d2b6e2be..b4a8da87 100644 --- a/app/src/main/java/org/osmtracker/listener/TagButtonOnClickListener.java +++ b/app/src/main/java/net/osmtracker/listener/TagButtonOnClickListener.java @@ -1,7 +1,7 @@ -package org.osmtracker.listener; +package net.osmtracker.listener; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; import android.content.Intent; import android.view.View; @@ -9,7 +9,7 @@ import android.widget.Button; import android.widget.Toast; -import org.osmtracker.db.TrackContentProvider; +import net.osmtracker.db.TrackContentProvider; /** * Listener for standard waypoint tag button. diff --git a/app/src/main/java/org/osmtracker/listener/TextNoteOnClickListener.java b/app/src/main/java/net/osmtracker/listener/TextNoteOnClickListener.java similarity index 82% rename from app/src/main/java/org/osmtracker/listener/TextNoteOnClickListener.java rename to app/src/main/java/net/osmtracker/listener/TextNoteOnClickListener.java index 5edb92ec..4d310091 100644 --- a/app/src/main/java/org/osmtracker/listener/TextNoteOnClickListener.java +++ b/app/src/main/java/net/osmtracker/listener/TextNoteOnClickListener.java @@ -1,6 +1,6 @@ -package org.osmtracker.listener; +package net.osmtracker.listener; -import org.osmtracker.activity.TrackLogger; +import net.osmtracker.activity.TrackLogger; import android.view.View; import android.view.View.OnClickListener; diff --git a/app/src/main/java/org/osmtracker/listener/VoiceRecOnClickListener.java b/app/src/main/java/net/osmtracker/listener/VoiceRecOnClickListener.java similarity index 85% rename from app/src/main/java/org/osmtracker/listener/VoiceRecOnClickListener.java rename to app/src/main/java/net/osmtracker/listener/VoiceRecOnClickListener.java index 6ea697f5..824b8ada 100644 --- a/app/src/main/java/org/osmtracker/listener/VoiceRecOnClickListener.java +++ b/app/src/main/java/net/osmtracker/listener/VoiceRecOnClickListener.java @@ -1,6 +1,6 @@ -package org.osmtracker.listener; +package net.osmtracker.listener; -import org.osmtracker.activity.TrackLogger; +import net.osmtracker.activity.TrackLogger; import android.view.View; import android.view.View.OnClickListener; diff --git a/app/src/main/java/org/osmtracker/osm/OpenStreetMapConstants.java b/app/src/main/java/net/osmtracker/osm/OpenStreetMapConstants.java similarity index 98% rename from app/src/main/java/org/osmtracker/osm/OpenStreetMapConstants.java rename to app/src/main/java/net/osmtracker/osm/OpenStreetMapConstants.java index e5aff310..e7424f75 100644 --- a/app/src/main/java/org/osmtracker/osm/OpenStreetMapConstants.java +++ b/app/src/main/java/net/osmtracker/osm/OpenStreetMapConstants.java @@ -1,4 +1,4 @@ -package org.osmtracker.osm; +package net.osmtracker.osm; public class OpenStreetMapConstants { diff --git a/app/src/main/java/org/osmtracker/osm/ProgressMultipartEntity.java b/app/src/main/java/net/osmtracker/osm/ProgressMultipartEntity.java similarity index 98% rename from app/src/main/java/org/osmtracker/osm/ProgressMultipartEntity.java rename to app/src/main/java/net/osmtracker/osm/ProgressMultipartEntity.java index 2effea1b..154e833a 100644 --- a/app/src/main/java/org/osmtracker/osm/ProgressMultipartEntity.java +++ b/app/src/main/java/net/osmtracker/osm/ProgressMultipartEntity.java @@ -1,4 +1,4 @@ -package org.osmtracker.osm; +package net.osmtracker.osm; import java.io.FilterOutputStream; import java.io.IOException; diff --git a/app/src/main/java/org/osmtracker/osm/RetrieveAccessTokenTask.java b/app/src/main/java/net/osmtracker/osm/RetrieveAccessTokenTask.java similarity index 92% rename from app/src/main/java/org/osmtracker/osm/RetrieveAccessTokenTask.java rename to app/src/main/java/net/osmtracker/osm/RetrieveAccessTokenTask.java index 8d282604..1dbcc3a3 100644 --- a/app/src/main/java/org/osmtracker/osm/RetrieveAccessTokenTask.java +++ b/app/src/main/java/net/osmtracker/osm/RetrieveAccessTokenTask.java @@ -1,9 +1,9 @@ -package org.osmtracker.osm; +package net.osmtracker.osm; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.activity.OpenStreetMapUpload; -import org.osmtracker.util.DialogUtils; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.activity.OpenStreetMapUpload; +import net.osmtracker.util.DialogUtils; import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer; import oauth.signpost.commonshttp.CommonsHttpOAuthProvider; diff --git a/app/src/main/java/org/osmtracker/osm/RetrieveRequestTokenTask.java b/app/src/main/java/net/osmtracker/osm/RetrieveRequestTokenTask.java similarity index 95% rename from app/src/main/java/org/osmtracker/osm/RetrieveRequestTokenTask.java rename to app/src/main/java/net/osmtracker/osm/RetrieveRequestTokenTask.java index b58a5681..e9871322 100644 --- a/app/src/main/java/org/osmtracker/osm/RetrieveRequestTokenTask.java +++ b/app/src/main/java/net/osmtracker/osm/RetrieveRequestTokenTask.java @@ -1,7 +1,7 @@ -package org.osmtracker.osm; +package net.osmtracker.osm; -import org.osmtracker.R; -import org.osmtracker.util.DialogUtils; +import net.osmtracker.R; +import net.osmtracker.util.DialogUtils; import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer; import oauth.signpost.commonshttp.CommonsHttpOAuthProvider; diff --git a/app/src/main/java/org/osmtracker/osm/UploadToOpenStreetMapTask.java b/app/src/main/java/net/osmtracker/osm/UploadToOpenStreetMapTask.java similarity index 97% rename from app/src/main/java/org/osmtracker/osm/UploadToOpenStreetMapTask.java rename to app/src/main/java/net/osmtracker/osm/UploadToOpenStreetMapTask.java index be9e8d43..572ac1e9 100644 --- a/app/src/main/java/org/osmtracker/osm/UploadToOpenStreetMapTask.java +++ b/app/src/main/java/net/osmtracker/osm/UploadToOpenStreetMapTask.java @@ -1,4 +1,4 @@ -package org.osmtracker.osm; +package net.osmtracker.osm; import java.io.BufferedInputStream; import java.io.BufferedReader; @@ -7,10 +7,10 @@ import java.io.InputStreamReader; import java.nio.charset.Charset; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.db.DataHelper; -import org.osmtracker.util.DialogUtils; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.db.DataHelper; +import net.osmtracker.util.DialogUtils; import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer; @@ -22,7 +22,7 @@ import org.apache.http.entity.mime.content.FileBody; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.impl.client.DefaultHttpClient; -import org.osmtracker.db.model.Track; +import net.osmtracker.db.model.Track; import android.app.Activity; import android.app.AlertDialog; diff --git a/app/src/main/java/org/osmtracker/overlay/WayPointsOverlay.java b/app/src/main/java/net/osmtracker/overlay/WayPointsOverlay.java similarity index 95% rename from app/src/main/java/org/osmtracker/overlay/WayPointsOverlay.java rename to app/src/main/java/net/osmtracker/overlay/WayPointsOverlay.java index 56ba15a9..4ee23ebf 100644 --- a/app/src/main/java/org/osmtracker/overlay/WayPointsOverlay.java +++ b/app/src/main/java/net/osmtracker/overlay/WayPointsOverlay.java @@ -1,10 +1,10 @@ -package org.osmtracker.overlay; +package net.osmtracker.overlay; import java.util.ArrayList; import java.util.List; -import org.osmtracker.R; -import org.osmtracker.db.TrackContentProvider; +import net.osmtracker.R; +import net.osmtracker.db.TrackContentProvider; import org.osmdroid.api.IMapView; import org.osmdroid.util.GeoPoint; diff --git a/app/src/main/java/org/osmtracker/receiver/MediaButtonReceiver.java b/app/src/main/java/net/osmtracker/receiver/MediaButtonReceiver.java similarity index 86% rename from app/src/main/java/org/osmtracker/receiver/MediaButtonReceiver.java rename to app/src/main/java/net/osmtracker/receiver/MediaButtonReceiver.java index d5826b54..113c54b1 100644 --- a/app/src/main/java/org/osmtracker/receiver/MediaButtonReceiver.java +++ b/app/src/main/java/net/osmtracker/receiver/MediaButtonReceiver.java @@ -1,6 +1,6 @@ -package org.osmtracker.receiver; +package net.osmtracker.receiver; -import org.osmtracker.activity.TrackLogger; +import net.osmtracker.activity.TrackLogger; import android.content.BroadcastReceiver; import android.content.Context; diff --git a/app/src/main/java/org/osmtracker/service/gps/GPSLogger.java b/app/src/main/java/net/osmtracker/service/gps/GPSLogger.java similarity index 87% rename from app/src/main/java/org/osmtracker/service/gps/GPSLogger.java rename to app/src/main/java/net/osmtracker/service/gps/GPSLogger.java index 8a8507fe..8c1105f5 100644 --- a/app/src/main/java/org/osmtracker/service/gps/GPSLogger.java +++ b/app/src/main/java/net/osmtracker/service/gps/GPSLogger.java @@ -1,12 +1,13 @@ -package org.osmtracker.service.gps; +package net.osmtracker.service.gps; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.activity.TrackLogger; -import org.osmtracker.db.DataHelper; -import org.osmtracker.db.TrackContentProvider; -import org.osmtracker.listener.SensorListener; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.activity.TrackLogger; +import net.osmtracker.db.DataHelper; +import net.osmtracker.db.TrackContentProvider; +import net.osmtracker.listener.SensorListener; +import android.Manifest; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -15,8 +16,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.location.GpsSatellite; -import android.location.GpsStatus; +import android.content.pm.PackageManager; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; @@ -24,6 +24,7 @@ import android.os.Bundle; import android.os.IBinder; import android.preference.PreferenceManager; +import android.support.v4.content.ContextCompat; import android.util.Log; /** @@ -106,14 +107,16 @@ public void onReceive(Context context, Intent intent) { if (extras != null) { // because of the gps logging interval our last fix could be very old // so we'll request the last known location from the gps provider - lastLocation = lmgr.getLastKnownLocation(LocationManager.GPS_PROVIDER); - if(lastLocation != null){ - Long trackId = extras.getLong(TrackContentProvider.Schema.COL_TRACK_ID); - String uuid = extras.getString(OSMTracker.INTENT_KEY_UUID); - String name = extras.getString(OSMTracker.INTENT_KEY_NAME); - String link = extras.getString(OSMTracker.INTENT_KEY_LINK); - - dataHelper.wayPoint(trackId, lastLocation, lastNbSatellites, name, link, uuid, sensorListener.getAzimuth(), sensorListener.getAccuracy()); + if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + lastLocation = lmgr.getLastKnownLocation(LocationManager.GPS_PROVIDER); + if (lastLocation != null) { + Long trackId = extras.getLong(TrackContentProvider.Schema.COL_TRACK_ID); + String uuid = extras.getString(OSMTracker.INTENT_KEY_UUID); + String name = extras.getString(OSMTracker.INTENT_KEY_NAME); + String link = extras.getString(OSMTracker.INTENT_KEY_LINK); + + dataHelper.wayPoint(trackId, lastLocation, lastNbSatellites, name, link, uuid, sensorListener.getAzimuth(), sensorListener.getAccuracy()); + } } } } else if (OSMTracker.INTENT_UPDATE_WP.equals(intent.getAction())) { @@ -205,7 +208,10 @@ public void onCreate() { // Register ourselves for location updates lmgr = (LocationManager) getSystemService(Context.LOCATION_SERVICE); - lmgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); + + if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + lmgr.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); + } //register for Orientation updates sensorListener.register(this); @@ -275,7 +281,7 @@ public void onLocationChanged(Location location) { lastGPSTimestamp = System.currentTimeMillis(); // save the time of this fix lastLocation = location; - lastNbSatellites = countSatellites(); + //lastNbSatellites = countSatellites(); if (isTracking) { dataHelper.track(currentTrackId, location, sensorListener.getAzimuth(), sensorListener.getAccuracy()); @@ -287,6 +293,7 @@ public void onLocationChanged(Location location) { * Counts number of satellites used in last fix. * @return The number of satellites */ + /* private int countSatellites() { int count = 0; GpsStatus status = lmgr.getGpsStatus(null); @@ -298,11 +305,12 @@ private int countSatellites() { return count; } + */ /** * Builds the notification to display when tracking in background. */ - private Notification getNotification() { + private Notification getNotification() { Notification n = new Notification(R.drawable.ic_stat_track, getResources().getString(R.string.notification_ticker_text), System.currentTimeMillis()); Intent startTrackLogger = new Intent(this, TrackLogger.class); diff --git a/app/src/main/java/org/osmtracker/service/gps/GPSLoggerServiceConnection.java b/app/src/main/java/net/osmtracker/service/gps/GPSLoggerServiceConnection.java similarity index 85% rename from app/src/main/java/org/osmtracker/service/gps/GPSLoggerServiceConnection.java rename to app/src/main/java/net/osmtracker/service/gps/GPSLoggerServiceConnection.java index ab4c5f2f..fcf26a7c 100644 --- a/app/src/main/java/org/osmtracker/service/gps/GPSLoggerServiceConnection.java +++ b/app/src/main/java/net/osmtracker/service/gps/GPSLoggerServiceConnection.java @@ -1,10 +1,10 @@ -package org.osmtracker.service.gps; +package net.osmtracker.service.gps; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.activity.TrackLogger; -import org.osmtracker.layout.GpsStatusRecord; -import org.osmtracker.db.TrackContentProvider; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.activity.TrackLogger; +import net.osmtracker.layout.GpsStatusRecord; +import net.osmtracker.db.TrackContentProvider; import android.content.ComponentName; import android.content.Intent; diff --git a/app/src/main/java/org/osmtracker/service/resources/AppResourceIconResolver.java b/app/src/main/java/net/osmtracker/service/resources/AppResourceIconResolver.java similarity index 91% rename from app/src/main/java/org/osmtracker/service/resources/AppResourceIconResolver.java rename to app/src/main/java/net/osmtracker/service/resources/AppResourceIconResolver.java index 39277acf..d8fcc38e 100644 --- a/app/src/main/java/org/osmtracker/service/resources/AppResourceIconResolver.java +++ b/app/src/main/java/net/osmtracker/service/resources/AppResourceIconResolver.java @@ -1,4 +1,4 @@ -package org.osmtracker.service.resources; +package net.osmtracker.service.resources; import android.content.res.Resources; import android.graphics.drawable.Drawable; diff --git a/app/src/main/java/org/osmtracker/service/resources/ExternalDirectoryIconResolver.java b/app/src/main/java/net/osmtracker/service/resources/ExternalDirectoryIconResolver.java similarity index 92% rename from app/src/main/java/org/osmtracker/service/resources/ExternalDirectoryIconResolver.java rename to app/src/main/java/net/osmtracker/service/resources/ExternalDirectoryIconResolver.java index ee358dde..bd14ec19 100644 --- a/app/src/main/java/org/osmtracker/service/resources/ExternalDirectoryIconResolver.java +++ b/app/src/main/java/net/osmtracker/service/resources/ExternalDirectoryIconResolver.java @@ -1,4 +1,4 @@ -package org.osmtracker.service.resources; +package net.osmtracker.service.resources; import java.io.File; diff --git a/app/src/main/java/org/osmtracker/service/resources/IconResolver.java b/app/src/main/java/net/osmtracker/service/resources/IconResolver.java similarity index 82% rename from app/src/main/java/org/osmtracker/service/resources/IconResolver.java rename to app/src/main/java/net/osmtracker/service/resources/IconResolver.java index a1a919ba..577a3552 100644 --- a/app/src/main/java/org/osmtracker/service/resources/IconResolver.java +++ b/app/src/main/java/net/osmtracker/service/resources/IconResolver.java @@ -1,4 +1,4 @@ -package org.osmtracker.service.resources; +package net.osmtracker.service.resources; import android.graphics.drawable.Drawable; diff --git a/app/src/main/java/org/osmtracker/util/ArrayUtils.java b/app/src/main/java/net/osmtracker/util/ArrayUtils.java similarity index 92% rename from app/src/main/java/org/osmtracker/util/ArrayUtils.java rename to app/src/main/java/net/osmtracker/util/ArrayUtils.java index 92ed03a4..036eb459 100644 --- a/app/src/main/java/org/osmtracker/util/ArrayUtils.java +++ b/app/src/main/java/net/osmtracker/util/ArrayUtils.java @@ -1,4 +1,4 @@ -package org.osmtracker.util; +package net.osmtracker.util; /** * Array utilities. diff --git a/app/src/main/java/org/osmtracker/util/DialogUtils.java b/app/src/main/java/net/osmtracker/util/DialogUtils.java similarity index 95% rename from app/src/main/java/org/osmtracker/util/DialogUtils.java rename to app/src/main/java/net/osmtracker/util/DialogUtils.java index d396bc36..8c00e6c6 100644 --- a/app/src/main/java/org/osmtracker/util/DialogUtils.java +++ b/app/src/main/java/net/osmtracker/util/DialogUtils.java @@ -1,4 +1,4 @@ -package org.osmtracker.util; +package net.osmtracker.util; import android.app.AlertDialog; import android.content.Context; diff --git a/app/src/main/java/org/osmtracker/util/FileSystemUtils.java b/app/src/main/java/net/osmtracker/util/FileSystemUtils.java similarity index 99% rename from app/src/main/java/org/osmtracker/util/FileSystemUtils.java rename to app/src/main/java/net/osmtracker/util/FileSystemUtils.java index 6050d0bf..b03492c5 100644 --- a/app/src/main/java/org/osmtracker/util/FileSystemUtils.java +++ b/app/src/main/java/net/osmtracker/util/FileSystemUtils.java @@ -1,4 +1,4 @@ -package org.osmtracker.util; +package net.osmtracker.util; import java.io.File; import java.io.FileInputStream; diff --git a/app/src/main/java/org/osmtracker/util/MercatorProjection.java b/app/src/main/java/net/osmtracker/util/MercatorProjection.java similarity index 95% rename from app/src/main/java/org/osmtracker/util/MercatorProjection.java rename to app/src/main/java/net/osmtracker/util/MercatorProjection.java index 55f13143..c3ba0ea3 100644 --- a/app/src/main/java/org/osmtracker/util/MercatorProjection.java +++ b/app/src/main/java/net/osmtracker/util/MercatorProjection.java @@ -1,4 +1,4 @@ -package org.osmtracker.util; +package net.osmtracker.util; /** diff --git a/app/src/main/java/org/osmtracker/util/ThemeValidator.java b/app/src/main/java/net/osmtracker/util/ThemeValidator.java similarity index 92% rename from app/src/main/java/org/osmtracker/util/ThemeValidator.java rename to app/src/main/java/net/osmtracker/util/ThemeValidator.java index 090e0c46..8ead833c 100644 --- a/app/src/main/java/org/osmtracker/util/ThemeValidator.java +++ b/app/src/main/java/net/osmtracker/util/ThemeValidator.java @@ -1,9 +1,9 @@ -package org.osmtracker.util; +package net.osmtracker.util; import java.util.Arrays; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; diff --git a/app/src/main/java/org/osmtracker/util/UserDefinedLayoutReader.java b/app/src/main/java/net/osmtracker/util/UserDefinedLayoutReader.java similarity index 95% rename from app/src/main/java/org/osmtracker/util/UserDefinedLayoutReader.java rename to app/src/main/java/net/osmtracker/util/UserDefinedLayoutReader.java index 73b64371..f42ec9db 100644 --- a/app/src/main/java/org/osmtracker/util/UserDefinedLayoutReader.java +++ b/app/src/main/java/net/osmtracker/util/UserDefinedLayoutReader.java @@ -1,19 +1,19 @@ -package org.osmtracker.util; +package net.osmtracker.util; import java.io.IOException; import java.util.HashMap; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.activity.TrackLogger; -import org.osmtracker.layout.DisablableTableLayout; -import org.osmtracker.layout.UserDefinedLayout; -import org.osmtracker.listener.PageButtonOnClickListener; -import org.osmtracker.listener.StillImageOnClickListener; -import org.osmtracker.listener.TagButtonOnClickListener; -import org.osmtracker.listener.TextNoteOnClickListener; -import org.osmtracker.listener.VoiceRecOnClickListener; -import org.osmtracker.service.resources.IconResolver; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.activity.TrackLogger; +import net.osmtracker.layout.DisablableTableLayout; +import net.osmtracker.layout.UserDefinedLayout; +import net.osmtracker.listener.PageButtonOnClickListener; +import net.osmtracker.listener.StillImageOnClickListener; +import net.osmtracker.listener.TagButtonOnClickListener; +import net.osmtracker.listener.TextNoteOnClickListener; +import net.osmtracker.listener.VoiceRecOnClickListener; +import net.osmtracker.service.resources.IconResolver; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; diff --git a/app/src/main/java/org/osmtracker/view/DisplayTrackView.java b/app/src/main/java/net/osmtracker/view/DisplayTrackView.java similarity index 94% rename from app/src/main/java/org/osmtracker/view/DisplayTrackView.java rename to app/src/main/java/net/osmtracker/view/DisplayTrackView.java index 638472f4..952bd7e5 100644 --- a/app/src/main/java/org/osmtracker/view/DisplayTrackView.java +++ b/app/src/main/java/net/osmtracker/view/DisplayTrackView.java @@ -1,11 +1,11 @@ -package org.osmtracker.view; +package net.osmtracker.view; import java.text.DecimalFormat; -import org.osmtracker.R; -import org.osmtracker.db.TrackContentProvider; -import org.osmtracker.util.ArrayUtils; -import org.osmtracker.util.MercatorProjection; +import net.osmtracker.R; +import net.osmtracker.db.TrackContentProvider; +import net.osmtracker.util.ArrayUtils; +import net.osmtracker.util.MercatorProjection; import android.content.Context; import android.database.ContentObserver; diff --git a/app/src/main/java/org/osmtracker/view/TextNoteDialog.java b/app/src/main/java/net/osmtracker/view/TextNoteDialog.java similarity index 96% rename from app/src/main/java/org/osmtracker/view/TextNoteDialog.java rename to app/src/main/java/net/osmtracker/view/TextNoteDialog.java index 781234fe..a5e4376a 100644 --- a/app/src/main/java/org/osmtracker/view/TextNoteDialog.java +++ b/app/src/main/java/net/osmtracker/view/TextNoteDialog.java @@ -1,9 +1,9 @@ -package org.osmtracker.view; +package net.osmtracker.view; import java.util.UUID; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; import android.app.AlertDialog; import android.content.Context; @@ -12,7 +12,7 @@ import android.os.Bundle; import android.widget.EditText; -import org.osmtracker.db.TrackContentProvider; +import net.osmtracker.db.TrackContentProvider; public class TextNoteDialog extends AlertDialog { diff --git a/app/src/main/java/org/osmtracker/view/VoiceRecDialog.java b/app/src/main/java/net/osmtracker/view/VoiceRecDialog.java similarity index 98% rename from app/src/main/java/org/osmtracker/view/VoiceRecDialog.java rename to app/src/main/java/net/osmtracker/view/VoiceRecDialog.java index 5f39f844..711ff0d1 100644 --- a/app/src/main/java/org/osmtracker/view/VoiceRecDialog.java +++ b/app/src/main/java/net/osmtracker/view/VoiceRecDialog.java @@ -1,13 +1,13 @@ -package org.osmtracker.view; +package net.osmtracker.view; import java.io.File; import java.util.Date; import java.util.UUID; -import org.osmtracker.OSMTracker; -import org.osmtracker.R; -import org.osmtracker.db.DataHelper; -import org.osmtracker.db.TrackContentProvider.Schema; +import net.osmtracker.OSMTracker; +import net.osmtracker.R; +import net.osmtracker.db.DataHelper; +import net.osmtracker.db.TrackContentProvider.Schema; import android.app.ProgressDialog; import android.content.Context; diff --git a/app/src/main/java/org/osmtracker/listener/StillImageOnClickListener.java b/app/src/main/java/org/osmtracker/listener/StillImageOnClickListener.java deleted file mode 100644 index 77817b97..00000000 --- a/app/src/main/java/org/osmtracker/listener/StillImageOnClickListener.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.osmtracker.listener; - -import org.osmtracker.activity.TrackLogger; -import android.view.View; -import android.view.View.OnClickListener; - -/** - * Manages still image recording with camera app. - * - * @author Nicolas Guillaumin - * - */ -public class StillImageOnClickListener implements OnClickListener { - - /** - * Parent activity - */ - TrackLogger activity; - - public StillImageOnClickListener(TrackLogger parent) { - activity = parent; - } - - @Override - public void onClick(View v) { - activity.requestStillImage(); - } - -} diff --git a/app/src/main/res/layout/trackdetail.xml b/app/src/main/res/layout/trackdetail.xml index bcf2f473..bc23256b 100644 --- a/app/src/main/res/layout/trackdetail.xml +++ b/app/src/main/res/layout/trackdetail.xml @@ -25,7 +25,7 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" - android:text="@android:R/string/cancel" /> + android:text="@string/menu_cancel" /> - diff --git a/app/src/main/res/values/values-preferences.xml b/app/src/main/res/values/values-preferences.xml index 961fad98..ae34c3e4 100644 --- a/app/src/main/res/values/values-preferences.xml +++ b/app/src/main/res/values/values-preferences.xml @@ -24,10 +24,10 @@ - org.osmtracker:style/DefaultTheme - org.osmtracker:style/DarkTheme - org.osmtracker:style/LightTheme - org.osmtracker:style/HighContrast + net.osmtracker:style/DefaultTheme + net.osmtracker:style/DarkTheme + net.osmtracker:style/LightTheme + net.osmtracker:style/HighContrast diff --git a/build.gradle b/build.gradle index 277c10f0..b6cb00b4 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:3.1.2' } }