From ae9b2d8fca3f102708931c310ae4069d597d7e9d Mon Sep 17 00:00:00 2001 From: y20k Date: Tue, 15 Aug 2017 10:23:03 +0200 Subject: [PATCH] some Android O-related fixes (location updates should continue to work - notification too) --- app/build.gradle | 4 +- app/src/main/AndroidManifest.xml | 1 + .../java/org/y20k/trackbook/MainActivity.java | 35 +++-- .../trackbook/MainActivityMapFragment.java | 30 ++-- .../org/y20k/trackbook/TrackerService.java | 110 +++++++++----- .../trackbook/helpers/NotificationHelper.java | 134 +++++++++--------- .../y20k/trackbook/helpers/TrackbookKeys.java | 3 + app/src/main/res/values-de/strings.xml | 2 + app/src/main/res/values-id/strings.xml | 121 +++++++++++++++- app/src/main/res/values-it/strings.xml | 2 + app/src/main/res/values-ja/strings.xml | 2 + app/src/main/res/values-nb-rNO/strings.xml | 2 + app/src/main/res/values-nl/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + build.gradle | 21 ++- 15 files changed, 319 insertions(+), 152 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index cc7a82b..8cd71e1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -25,6 +25,6 @@ dependencies { compile 'com.android.support:appcompat-v7:' + supportLibraryVersion compile 'com.android.support:design:' + supportLibraryVersion compile 'com.android.support:cardview-v7:' + supportLibraryVersion - compile 'org.osmdroid:osmdroid-android:5.6.5' - compile 'com.google.code.gson:gson:2.8.1' + compile 'org.osmdroid:osmdroid-android:' + osmdroidVersion + compile 'com.google.code.gson:gson:' + gsonVersion } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8017a70..bb50bd7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -58,6 +58,7 @@ + diff --git a/app/src/main/java/org/y20k/trackbook/MainActivity.java b/app/src/main/java/org/y20k/trackbook/MainActivity.java index 6a7be77..66cef11 100644 --- a/app/src/main/java/org/y20k/trackbook/MainActivity.java +++ b/app/src/main/java/org/y20k/trackbook/MainActivity.java @@ -54,7 +54,6 @@ import android.widget.Toast; import org.y20k.trackbook.helpers.DialogHelper; import org.y20k.trackbook.helpers.LogHelper; -import org.y20k.trackbook.helpers.NotificationHelper; import org.y20k.trackbook.helpers.TrackbookKeys; import org.y20k.trackbook.layout.NonSwipeableViewPager; @@ -192,8 +191,8 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys { protected void onPause() { super.onPause(); - // save state of Floating Action Button - saveFloatingActionButtonState(this); +// // save state of Floating Action Button +// saveFloatingActionButtonState(this); } @@ -291,7 +290,9 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys { mViewPager.setCurrentItem(mSelectedTab); // dismiss notification - NotificationHelper.stop(); + Intent intent = new Intent(this, TrackerService.class); + intent.setAction(ACTION_DISMISS); + startService(intent); // hide Floating Action Button sub menu showFloatingActionButtonMenu(false); @@ -308,7 +309,9 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys { Toast.makeText(this, getString(R.string.toast_message_track_clear), Toast.LENGTH_LONG).show(); // dismiss notification - NotificationHelper.stop(); + Intent intent = new Intent(this, TrackerService.class); + intent.setAction(ACTION_DISMISS); + startService(intent); // hide Floating Action Button sub menu showFloatingActionButtonMenu(false); @@ -326,13 +329,13 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys { } - /* Saves state of Floating Action Button */ - private void saveFloatingActionButtonState(Context context) { - SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); - SharedPreferences.Editor editor = settings.edit(); - editor.putInt(PREFS_FAB_STATE, mFloatingActionButtonState); - editor.apply(); - } +// /* Saves state of Floating Action Button */ +// private void saveFloatingActionButtonState(Context context) { +// SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); +// SharedPreferences.Editor editor = settings.edit(); +// editor.putInt(PREFS_FAB_STATE, mFloatingActionButtonState); +// editor.apply(); +// } /* Set up main layout */ @@ -480,7 +483,13 @@ public class MainActivity extends AppCompatActivity implements TrackbookKeys { Intent intent = new Intent(this, TrackerService.class); intent.setAction(ACTION_START); intent.putExtra(EXTRA_LAST_LOCATION, lastLocation); - startService(intent); +// startService(intent); + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) { + startForegroundService(intent); + } else { + startService(intent); + } + } else { Toast.makeText(this, getString(R.string.toast_message_location_services_not_ready), Toast.LENGTH_LONG).show(); // change state back diff --git a/app/src/main/java/org/y20k/trackbook/MainActivityMapFragment.java b/app/src/main/java/org/y20k/trackbook/MainActivityMapFragment.java index b21c218..476a2cd 100644 --- a/app/src/main/java/org/y20k/trackbook/MainActivityMapFragment.java +++ b/app/src/main/java/org/y20k/trackbook/MainActivityMapFragment.java @@ -194,10 +194,10 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys { mFirstStart = false; } - // load track from saved instance - if (savedInstanceState != null) { - mTrack = savedInstanceState.getParcelable(INSTANCE_TRACK_MAIN_MAP); - } +// // load track from saved instance +// if (savedInstanceState != null) { +// mTrack = savedInstanceState.getParcelable(INSTANCE_TRACK_MAIN_MAP); +// } // mark user's location on map if (mCurrentBestLocation != null && !mTrackerServiceRunning) { @@ -222,9 +222,9 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys { // CASE 1: recording active if (mTrackerServiceRunning) { // request an updated track recording from service - Intent i = new Intent(); - i.setAction(ACTION_TRACK_REQUEST); - LocalBroadcastManager.getInstance(mActivity).sendBroadcast(i); + Intent intent = new Intent(mActivity, TrackerService.class); + intent.setAction(ACTION_TRACK_REQUEST); + mActivity.startService(intent); } // CASE 2: recording stopped - temp file exists @@ -232,13 +232,14 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys { // load track from temp file if it exists LoadTempTrackAsyncHelper loadTempTrackAsyncHelper = new LoadTempTrackAsyncHelper(); loadTempTrackAsyncHelper.execute(); - - // CASE 3: not recording and no temp file - } else if (mTrack != null) { - // just draw existing track data (from saved instance) - drawTrackOverlay(mTrack); } +// // CASE 3: not recording and no temp file +// else if (mTrack != null) { +// // just draw existing track data (from saved instance) +// drawTrackOverlay(mTrack); +// } + // show/hide the location off notification bar toggleLocationOffBar(); @@ -385,7 +386,7 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys { outState.putDouble(INSTANCE_LATITUDE_MAIN_MAP, mMapView.getMapCenter().getLatitude()); outState.putDouble(INSTANCE_LONGITUDE_MAIN_MAP, mMapView.getMapCenter().getLongitude()); outState.putInt(INSTANCE_ZOOM_LEVEL_MAIN_MAP, mMapView.getZoomLevel()); - outState.putParcelable(INSTANCE_TRACK_MAIN_MAP, mTrack); +// outState.putParcelable(INSTANCE_TRACK_MAIN_MAP, mTrack); super.onSaveInstanceState(outState); } @@ -581,8 +582,7 @@ public class MainActivityMapFragment extends Fragment implements TrackbookKeys { /* Loads state tracker service from preferences */ private void loadTrackerServiceState(Context context) { SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); - int fabState = settings.getInt(PREFS_FAB_STATE, FAB_STATE_DEFAULT); - mTrackerServiceRunning = fabState == FAB_STATE_RECORDING; + mTrackerServiceRunning = settings.getBoolean(PREFS_TRACKER_SERVICE_RUNNING, false); } diff --git a/app/src/main/java/org/y20k/trackbook/TrackerService.java b/app/src/main/java/org/y20k/trackbook/TrackerService.java index 842e869..a6cb245 100644 --- a/app/src/main/java/org/y20k/trackbook/TrackerService.java +++ b/app/src/main/java/org/y20k/trackbook/TrackerService.java @@ -16,11 +16,11 @@ package org.y20k.trackbook; +import android.app.Notification; +import android.app.NotificationManager; import android.app.Service; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.SharedPreferences; import android.database.ContentObserver; import android.hardware.Sensor; @@ -37,6 +37,7 @@ import android.os.Handler; import android.os.IBinder; import android.preference.PreferenceManager; import android.support.annotation.Nullable; +import android.support.v4.app.NotificationCompat; import android.support.v4.content.LocalBroadcastManager; import android.widget.Toast; @@ -70,7 +71,9 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven private LocationListener mNetworkListener = null; private SettingsContentObserver mSettingsContentObserver; private Location mCurrentBestLocation; - private BroadcastReceiver mTrackRequestReceiver; + private Notification mNotification; + private NotificationCompat.Builder mNotificationBuilder; + private NotificationManager mNotificationManager; private boolean mTrackerServiceRunning; private boolean mLocationSystemSetting; @@ -79,15 +82,9 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven public void onCreate() { super.onCreate(); - // receiver: listen track request issued by the main map - in onResume - mTrackRequestReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - sendTrackUpdate(); - } - }; - IntentFilter trackRequestReceiverIntentFilter = new IntentFilter(ACTION_TRACK_REQUEST); - LocalBroadcastManager.getInstance(this).registerReceiver(mTrackRequestReceiver, trackRequestReceiverIntentFilter); + // prepare notification channel and get NotificationManager + mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + NotificationHelper.createNotificationChannel(this); // acquire reference to Location Manager mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); @@ -100,7 +97,6 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven // create content observer for changes in System Settings mSettingsContentObserver = new SettingsContentObserver(new Handler()); - } @@ -116,7 +112,7 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven } // checking for empty intent - if (intent == null) { + if (intent == null || intent.getAction() == null) { LogHelper.e(LOG_TAG, "Null-Intent received. Stopping self."); // stopSelf triggers onDestroy stopSelf(); @@ -129,15 +125,28 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven // ACTION STOP else if (intent.getAction().equals(ACTION_STOP) || !mLocationSystemSetting) { + mTrackerServiceRunning = false; if (mTrack != null && mTimer != null) { stopTracking(); + } else { + // handle error - save state + saveTrackerServiceState(mTrackerServiceRunning, FAB_STATE_DEFAULT); } + } - // save changed state of Floating Action Button - SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext()); - SharedPreferences.Editor editor = settings.edit(); - editor.putInt(PREFS_FAB_STATE, FAB_STATE_SAVE); - editor.apply(); + // ACTION DISMISS + else if (intent.getAction().equals(ACTION_DISMISS)) { + // save state + saveTrackerServiceState(mTrackerServiceRunning, FAB_STATE_DEFAULT); + // dismiss notification + mNotificationManager.cancel(TRACKER_SERVICE_NOTIFICATION_ID); // todo check if necessary? + stopForeground(true); + } + + // ACTION TRACK REQUEST + else if (intent.getAction().equals(ACTION_TRACK_REQUEST)) { + // send track via broadcast + sendTrackUpdate(); } // START_STICKY is used for services that are explicitly started and stopped as needed @@ -156,12 +165,15 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven public void onDestroy() { LogHelper.v(LOG_TAG, "onDestroy called."); - // remove receivers and listeners - stopFindingLocation(); - mSensorManager.unregisterListener(this); - LocalBroadcastManager.getInstance(this).unregisterReceiver(mTrackRequestReceiver); + if (mTrackerServiceRunning) { + stopTracking(); + } - // cancel notification +// // remove listeners +// stopFindingLocation(); +// mSensorManager.unregisterListener(this); + + // todo describe stopForeground(true); super.onDestroy(); @@ -208,6 +220,11 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven // add last location as WayPoint to track addWayPointToTrack(); + // put up notification + mNotificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANEL_ID_RECORDING_CHANNEL); + mNotification = NotificationHelper.getNotification(this, mNotificationBuilder, mTrack, true); + mNotificationManager.notify(TRACKER_SERVICE_NOTIFICATION_ID, mNotification); // todo check if necessary in pre Android O + // set timer to retrieve new locations and to prevent endless tracking mTimer = new CountDownTimer(EIGHT_HOURS_IN_MILLISECONDS, FIFTEEN_SECONDS_IN_MILLISECONDS) { @Override @@ -218,13 +235,14 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven // try to add WayPoint to Track addWayPointToTrack(); // update notification - NotificationHelper.update(mTrack, true); + mNotification = NotificationHelper.getUpdatedNotification(TrackerService.this, mNotificationBuilder, mTrack); + mNotificationManager.notify(TRACKER_SERVICE_NOTIFICATION_ID, mNotification); } @Override public void onFinish() { - // remove listeners - stopFindingLocation(); + // stop tracking after eight hours + stopTracking(); } }; mTimer.start(); @@ -239,14 +257,14 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven mTrack.setStepCount(-1); } - // put up notification - NotificationHelper.show(this,mTrack); - // create gps and network location listeners startFindingLocation(); // register content observer for changes in System Settings - this.getContentResolver().registerContentObserver(android.provider.Settings.Secure.CONTENT_URI, true, mSettingsContentObserver ); + this.getContentResolver().registerContentObserver(android.provider.Settings.Secure.CONTENT_URI, true, mSettingsContentObserver); + + // start service in foreground + startForeground(TRACKER_SERVICE_NOTIFICATION_ID, mNotification); } @@ -268,7 +286,9 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven saveTempTrackAsyncHelper.execute(); // change notification - NotificationHelper.update(mTrack, false); + mNotificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANEL_ID_RECORDING_CHANNEL); + mNotification = NotificationHelper.getNotification(this, mNotificationBuilder, mTrack, false); + mNotificationManager.notify(TRACKER_SERVICE_NOTIFICATION_ID, mNotification); // remove listeners stopFindingLocation(); @@ -276,6 +296,9 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven // disable content observer for changes in System Settings this.getContentResolver().unregisterContentObserver(mSettingsContentObserver); + + // todo describe + stopForeground(false); } @@ -303,7 +326,7 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven Location firstWayPoint = mTrack.getWayPointLocation(0); float distance = firstWayPoint.distanceTo(lastWayPoint); long timeDifference = lastWayPoint.getElapsedRealtimeNanos() - firstWayPoint.getElapsedRealtimeNanos(); - averageSpeed = distance / ((float)timeDifference / ONE_NANOSECOND); + averageSpeed = distance / ((float) timeDifference / ONE_NANOSECOND); } if (LocationHelper.isNewWayPoint(lastWayPoint, mCurrentBestLocation, averageSpeed)) { @@ -345,15 +368,15 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven } public void onStatusChanged(String provider, int status, Bundle extras) { - LogHelper.v(LOG_TAG, "Location provider status change: " + provider + " | " + status); + LogHelper.v(LOG_TAG, "Location provider status change: " + provider + " | " + status); } public void onProviderEnabled(String provider) { - LogHelper.v(LOG_TAG, "Location provider enabled: " + provider); + LogHelper.v(LOG_TAG, "Location provider enabled: " + provider); } public void onProviderDisabled(String provider) { - LogHelper.v(LOG_TAG, "Location provider disabled: " + provider); + LogHelper.v(LOG_TAG, "Location provider disabled: " + provider); } }; } @@ -373,6 +396,7 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven mTrackerServiceRunning = true; } LocationHelper.registerLocationListeners(mLocationManager, mGPSListener, mNetworkListener); + saveTrackerServiceState(mTrackerServiceRunning, FAB_STATE_RECORDING); } @@ -381,6 +405,7 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven // remove listeners LocationHelper.removeLocationListeners(mLocationManager, mGPSListener, mNetworkListener); mTrackerServiceRunning = false; + saveTrackerServiceState(mTrackerServiceRunning, FAB_STATE_SAVE); // notify MainActivityMapFragment Intent i = new Intent(); @@ -391,6 +416,16 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven } + /* Saves state of Tracker Service and floating Action Button */ + private void saveTrackerServiceState(boolean trackerServiceRunning, int fabState) { + SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this); + SharedPreferences.Editor editor = settings.edit(); + editor.putBoolean(PREFS_TRACKER_SERVICE_RUNNING, trackerServiceRunning); + editor.putInt(PREFS_FAB_STATE, fabState); + editor.apply(); + } + + /** * Inner class: SettingsContentObserver is a custom ContentObserver for changes in Android Settings */ @@ -452,5 +487,4 @@ public class TrackerService extends Service implements TrackbookKeys, SensorEven * End of inner class */ - -} +} \ No newline at end of file diff --git a/app/src/main/java/org/y20k/trackbook/helpers/NotificationHelper.java b/app/src/main/java/org/y20k/trackbook/helpers/NotificationHelper.java index 232db7c..06ddd29 100644 --- a/app/src/main/java/org/y20k/trackbook/helpers/NotificationHelper.java +++ b/app/src/main/java/org/y20k/trackbook/helpers/NotificationHelper.java @@ -17,17 +17,18 @@ package org.y20k.trackbook.helpers; import android.app.Notification; +import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; -import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.os.Build; import android.support.graphics.drawable.VectorDrawableCompat; +import android.support.v4.app.NotificationCompat; import android.support.v4.app.TaskStackBuilder; -import android.support.v7.app.NotificationCompat; import org.y20k.trackbook.MainActivity; import org.y20k.trackbook.R; @@ -44,110 +45,96 @@ public class NotificationHelper implements TrackbookKeys { private static final String LOG_TAG = NotificationHelper.class.getSimpleName(); - /* Main class variables */ - private static Notification mNotification; - private static Service mService; - - - /* Create and put up notification */ - public static void show(final Service service, Track track) { - // save service - mService = service; - - // build notification - mNotification = getNotificationBuilder(track, true).build(); - - // display notification - mService.startForeground(TRACKER_SERVICE_NOTIFICATION_ID, mNotification); - } - - - /* Updates the notification */ - public static void update(Track track, boolean tracking) { - - // build notification - mNotification = getNotificationBuilder(track, tracking).build(); - - // display updated notification - NotificationManager notificationManager = (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.notify(TRACKER_SERVICE_NOTIFICATION_ID, mNotification); - - if (!tracking) { - // make notification swipe-able - mService.stopForeground(false); - } - - } - - - /* Stop displaying notification */ - public static void stop() { - if (mService != null) { - mService.stopForeground(true); - } - } - - /* Creates a notification builder */ - private static NotificationCompat.Builder getNotificationBuilder(Track track, boolean tracking) { + public static Notification getNotification(Context context, NotificationCompat.Builder builder, Track track, boolean tracking) { - String contentText = mService.getString(R.string.notification_content_distance) + ": " + track.getTrackDistance() + " | " + - mService.getString(R.string.notification_content_duration) + ": " + track.getTrackDuration(); + // create notification channel + createNotificationChannel(context); + + // build context text for notification builder + String contentText = getContextString(context, track); // ACTION: NOTIFICATION TAP - Intent tapActionIntent = new Intent(mService, MainActivity.class); + Intent tapActionIntent = new Intent(context, MainActivity.class); tapActionIntent.setAction(ACTION_SHOW_MAP); tapActionIntent.putExtra(EXTRA_TRACK, track); tapActionIntent.putExtra(EXTRA_TRACKING_STATE, tracking); // artificial back stack for started Activity (https://developer.android.com/training/notify-user/navigation.html#DirectEntry) - TaskStackBuilder tapActionIntentBuilder = TaskStackBuilder.create(mService); + TaskStackBuilder tapActionIntentBuilder = TaskStackBuilder.create(context); tapActionIntentBuilder.addParentStack(MainActivity.class); tapActionIntentBuilder.addNextIntent(tapActionIntent); // pending intent wrapper for notification tap PendingIntent tapActionPendingIntent = tapActionIntentBuilder.getPendingIntent(10, PendingIntent.FLAG_UPDATE_CURRENT); - // ACTION: NOTIFICATION BUTTON STOP - Intent stopActionIntent = new Intent(mService, TrackerService.class); + Intent stopActionIntent = new Intent(context, TrackerService.class); stopActionIntent.setAction(ACTION_STOP); // pending intent wrapper for notification stop action - PendingIntent stopActionPendingIntent = PendingIntent.getService(mService, 12, stopActionIntent, 0); - + PendingIntent stopActionPendingIntent = PendingIntent.getService(context, 12, stopActionIntent, 0); // construct notification in builder - NotificationCompat.Builder builder; - builder = new NotificationCompat.Builder(mService); builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC); builder.setShowWhen(false); builder.setContentIntent(tapActionPendingIntent); builder.setSmallIcon(R.drawable.ic_notification_small_24dp); - builder.setLargeIcon(getNotificationIconLarge(tracking)); + builder.setLargeIcon(getNotificationIconLarge(context, tracking)); if (tracking) { - builder.addAction(R.drawable.ic_stop_white_36dp, mService.getString(R.string.notification_stop), stopActionPendingIntent); - builder.setContentTitle(mService.getString(R.string.notification_title_trackbook_running)); - builder.setContentText(contentText); + builder.addAction(R.drawable.ic_stop_white_36dp, context.getString(R.string.notification_stop), stopActionPendingIntent); + builder.setContentTitle(context.getString(R.string.notification_title_trackbook_running)); + builder.setContentText(getContextString(context, track)); } else { - builder.setContentTitle(mService.getString(R.string.notification_title_trackbook_not_running)); - builder.setContentText(contentText); + builder.setContentTitle(context.getString(R.string.notification_title_trackbook_not_running)); + builder.setContentText(getContextString(context, track)); } - return builder; + return builder.build(); + } + + + /* Constructs an updated notification */ + public static Notification getUpdatedNotification(Context context, NotificationCompat.Builder builder, Track track) { + builder.setContentText(getContextString(context, track)); + return builder.build(); + } + + + /* Create a notification channel */ + public static boolean createNotificationChannel(Context context) { + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // API level 26 ("Android O") supports notification channels. + String id = NOTIFICATION_CHANEL_ID_RECORDING_CHANNEL; + CharSequence name = context.getString(R.string.notification_channel_recording_name); + String description = context.getString(R.string.notification_channel_recording_description); + int importance = NotificationManager.IMPORTANCE_LOW; + + // create channel + NotificationChannel channel = new NotificationChannel(id, name, importance); + channel.setDescription(description); + + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.createNotificationChannel(channel); + return true; + + } else { + return false; + } } /* Get station image for notification's large icon */ - private static Bitmap getNotificationIconLarge(boolean tracking) { + private static Bitmap getNotificationIconLarge(Context context, boolean tracking) { // get dimensions - Resources resources = mService.getResources(); + Resources resources = context.getResources(); int height = (int) resources.getDimension(android.R.dimen.notification_large_icon_height); int width = (int) resources.getDimension(android.R.dimen.notification_large_icon_width); Bitmap bitmap; if (tracking) { - bitmap = getBitmap(R.drawable.ic_notification_large_tracking_48dp); + bitmap = getBitmap(context, R.drawable.ic_notification_large_tracking_48dp); } else { - bitmap = getBitmap(R.drawable.ic_notification_large_not_tracking_48dp); + bitmap = getBitmap(context, R.drawable.ic_notification_large_not_tracking_48dp); } return Bitmap.createScaledBitmap(bitmap, width, height, false); @@ -155,8 +142,8 @@ public class NotificationHelper implements TrackbookKeys { /* Return a bitmap for a given resource id of a vector drawable */ - private static Bitmap getBitmap(int resource) { - VectorDrawableCompat drawable = VectorDrawableCompat.create(mService.getResources(), resource, null); + private static Bitmap getBitmap(Context context, int resource) { + VectorDrawableCompat drawable = VectorDrawableCompat.create(context.getResources(), resource, null); if (drawable != null) { Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); @@ -168,4 +155,11 @@ public class NotificationHelper implements TrackbookKeys { } } + + /* Build context text for notification builder */ + private static String getContextString(Context context, Track track) { + return context.getString(R.string.notification_content_distance) + ": " + track.getTrackDistance() + " | " + + context.getString(R.string.notification_content_duration) + ": " + track.getTrackDuration(); + } + } diff --git a/app/src/main/java/org/y20k/trackbook/helpers/TrackbookKeys.java b/app/src/main/java/org/y20k/trackbook/helpers/TrackbookKeys.java index c3f1cb5..736d32d 100644 --- a/app/src/main/java/org/y20k/trackbook/helpers/TrackbookKeys.java +++ b/app/src/main/java/org/y20k/trackbook/helpers/TrackbookKeys.java @@ -25,6 +25,7 @@ public interface TrackbookKeys { /* ACTIONS */ String ACTION_START = "org.y20k.trackbook.action.START"; String ACTION_STOP = "org.y20k.trackbook.action.STOP"; + String ACTION_DISMISS = "org.y20k.transistor.action.DISMISS"; String ACTION_DEFAULT = "DEFAULT"; String ACTION_SHOW_MAP = "SHOW_MAP"; String ACTION_TRACK_UPDATED = "TRACK_UPDATED"; @@ -54,6 +55,7 @@ public interface TrackbookKeys { /* PREFS */ String PREFS_FAB_STATE = "fabStatePrefs"; + String PREFS_TRACKER_SERVICE_RUNNING = "trackerServiceRunning"; /* INSTANCE STATE */ String INSTANCE_FIRST_START = "firstStart"; @@ -112,6 +114,7 @@ public interface TrackbookKeys { String FILE_TYPE_TRACKBOOK_EXTENSION = ".trackbook"; String FILE_NAME_TEMP = "temp"; + String NOTIFICATION_CHANEL_ID_RECORDING_CHANNEL ="notificationChannelIdRecordingChannel"; double DEFAULT_LATITUDE = 49.41667; // latitude Nordkapp, Norway double DEFAULT_LONGITUDE = 8.67201; // longitude Nordkapp, Norway diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index d70a6c1..0ed72c5 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -23,6 +23,8 @@ (Ausblenden setzt Kartenansicht zurück) Dauer Entfernung + Status der Aufzeichnung + Dauer- und Entfernungsanzeige. Option die Aufzeichnung von Standort-Bewegungen zu beenden. Tracking deaktiviert diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index 0ba3bfb..04c0431 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -1,22 +1,139 @@ -Trackbook Infosheet + + + Trackbook + Infosheet + Lokasi Saya Tentang + Tentang Trackbook + PETA JALUR TERAKHIR JALUR TERAKHIR + Trackbook aktif Trackbook tidak aktif Berhenti (geser untuk menghapus peta) Durasi Jarak + Movement Recording State + Display duration and distance. Option to stop movement recording. + Pelacakan berhenti Pelacakan dimulai - + Location is turned off. Trackbook will not work. + + + Clear + Save and Clear + + + Cancel + Clear Recording? + Clear + Delete Recording? + Delete this recording: + Delete + Export Recording as GPX? + Export this recording as GPX track. + Export + Export and Overwrite? + File already exists. Export and overwrite this recording as GPX track. + Export and Overwrite + + + Permissions granted. + Unable to start Trackbook. + Unable to access external storage. + Location is turned off. Trackbook will not work. + Acquiring current location. + Location services not ready. Please retry. + Last location: + Saving current track. + over one hour + Current track data removed. + GPX export successful: + GPX export failed: + + + Source + Time + Accuracy + + + Statistics + track data missing + Total distance: + Steps taken: + Recorded waypoints: + Total duration: + Recording started: + Recording stopped: + + + Hello + Trackbook App Icon + Trackbook + Movement Recorder for Android + Trackbook cannot work without these permissions: + LOCATION + Trackbook needs accurate GPS data to be able to record your movements. If the GPS data is not available or not accurate enough, Trackbook uses location data from cell tower and Wi-Fi triangulation. + STORAGE + Trackbook uses osmdroid, which caches map tiles on Android\'s external storage. You can find the map cache in the osmdroid folder on the top level of the user-facing file system. + Got it! + + + Your recorded tracks + … will show up here. + + + About Trackbook + Movement Recorder for Android + Version 1.0 (Astronomy Domine) + Trackbook is a bare bones app for recording your movements. Trackbook is great for hiking, vacation or workout. Once started it traces your movements on a map. The map data is provided by OpenStreetMap (OSM). + Trackbook is free software. You can find the code on GitHub. GitHub is also a good place to file bugs or even to contribute, if you are interested. Trackbook is published under the MIT open source license. Trackbook uses osmdroid to display the map, which is also free software published under the Apache License. + Which Permissions does Trackbook need? + Permission INTERNET + Trackbook needs to download map data from OpenStreetMap servers and therefore needs access to the internet. + Permissions ACCESS_WIFI_STATE and ACCESS_NETWORK_STATE + Trackbook uses osmdroid to draw its maps. osmdroid needs to know the current state of your device’s connectivity. + Permissions ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION + Trackbook needs accurate GPS location data to be able to record your movements. If the GPS data is not available or not accurate enough Trackbook uses location data from cell tower and WiFi triangulation. + Permission WRITE_EXTERNAL_STORAGE + Trackbook uses osmdroid, which caches map tiles on Android\'s external storage. You can find the map cache in the osmdroid folder on the top level of the user-facing file system. + + + Mapping of current track + Mapping of last track + Main Action Button + Label of the Save and Clear button + small Save and Clear button + Label of the Clear button + small Clear button + Headline of the statistics sheet + Icon of a bar chart + Data point: Distance + Data point: Steps + Data point: Waypoints + Data point: Duration + Data point: Start of recording + Data point: End of recording + Value: Distance + Value: Steps + Value: Waypoints + Value: Duration + Value: Start of recording + Value: End of recording + Dropdown menu for further tracks + Track export button + Track delete button + + diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 4f711a5..ce91c29 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -23,6 +23,8 @@ (scorri per spostare la mappa) Durata Distanza + Movement Recording State + Display duration and distance. Option to stop movement recording. Tracciamento interrotto diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index cc13d8d..d2da693 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -18,6 +18,8 @@ (スワイプしてマップをクリア) 期間 距離 + Movement Recording State + Display duration and distance. Option to stop movement recording. トレースを停止しました トレースを開始しました diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 881b9ee..5b9dd43 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -18,6 +18,8 @@ (sveip for å tømme kart) Varighet Distanse + Movement Recording State + Display duration and distance. Option to stop movement recording. Sporing stoppet Sporing startet diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index b0ab031..9d96cbc 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -18,6 +18,8 @@ (veeg om kaart te wissen) Duur Afstand + Movement Recording State + Display duration and distance. Option to stop movement recording. Bijhouden gestopt Bijhouden gestart diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 05ea965..44705a6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -23,6 +23,8 @@ (swipe to clear map) Duration Distance + Movement Recording State + Display duration and distance. Option to stop movement recording. Tracking stopped diff --git a/build.gradle b/build.gradle index 712650e..b043655 100644 --- a/build.gradle +++ b/build.gradle @@ -21,19 +21,16 @@ allprojects { } project.ext { applicationId = 'org.y20k.trackbook' - versionCode = 12 - versionName = '1.0.5 (Astronomy Domine)' + versionCode = 13 + versionName = '1.0.6 (Astronomy Domine)' minSdkVersion = 22 - // Android N - release - compileSdkVersion = 25 - targetSdkVersion = 25 - buildToolsVersion = '25.0.3 ' - supportLibraryVersion = '25.4.0' - // Android O - test -// compileSdkVersion = 26 -// targetSdkVersion = 26 -// buildToolsVersion = '26.0.0' -// supportLibraryVersion = '26.0.0-beta2' + compileSdkVersion = 26 + targetSdkVersion = 26 + buildToolsVersion = '26.0.1' + supportLibraryVersion = '26.0.1' + + osmdroidVersion = '5.6.5' + gsonVersion = '2.8.1' } }