some Android O-related fixes (location updates should continue to work - notification too)

master
y20k 2017-08-15 10:23:03 +02:00
parent 419448bcbd
commit ae9b2d8fca
15 changed files with 319 additions and 152 deletions

View File

@ -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
}

View File

@ -58,6 +58,7 @@
<intent-filter>
<action android:name="org.y20k.trackbook.action.START" />
<action android:name="org.y20k.trackbook.action.STOP" />
<action android:name="org.y20k.trackbook.action.DISMISS" />
</intent-filter>
</service>

View File

@ -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);
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

View File

@ -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);
}

View File

@ -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)) {
@ -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
*/
}

View File

@ -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();
}
}

View File

@ -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

View File

@ -23,6 +23,8 @@
<string name="notification_swipe_to_clear_map">(Ausblenden setzt Kartenansicht zurück)</string>
<string name="notification_content_duration">Dauer</string>
<string name="notification_content_distance">Entfernung</string>
<string name="notification_channel_recording_name">Status der Aufzeichnung</string>
<string name="notification_channel_recording_description">Dauer- und Entfernungsanzeige. Option die Aufzeichnung von Standort-Bewegungen zu beenden.</string>
<!-- snackbar messages -->
<string name="snackbar_message_tracking_stopped">Tracking deaktiviert</string>

View File

@ -1,22 +1,139 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources><string name="app_name">Trackbook</string> <string name="title_activity_infosheet">Infosheet</string>
<resources>
<!-- activities -->
<string name="app_name">Trackbook</string>
<string name="title_activity_infosheet">Infosheet</string>
<!-- menu entries -->
<string name="menu_my_location">Lokasi Saya</string>
<string name="menu_about">Tentang</string>
<!-- headers -->
<string name="header_about">Tentang Trackbook</string>
<!-- tabs -->
<string name="tab_map">PETA</string>
<string name="tab_last_track">JALUR TERAKHIR</string>
<string name="tab_last_tracks">JALUR TERAKHIR</string>
<!-- notification -->
<string name="notification_title_trackbook_running">Trackbook aktif</string>
<string name="notification_title_trackbook_not_running">Trackbook tidak aktif</string>
<string name="notification_stop">Berhenti</string>
<string name="notification_swipe_to_clear_map">(geser untuk menghapus peta)</string>
<string name="notification_content_duration">Durasi</string>
<string name="notification_content_distance">Jarak</string>
<string name="notification_channel_recording_name">Movement Recording State</string>
<string name="notification_channel_recording_description">Display duration and distance. Option to stop movement recording.</string>
<!-- snackbar messages -->
<string name="snackbar_message_tracking_stopped">Pelacakan berhenti</string>
<string name="snackbar_message_tracking_started">Pelacakan dimulai</string>
</resources>
<string name="snackbar_message_location_offline">Location is turned off. Trackbook will not work.</string>
<!-- fab sub menu -->
<string name="fab_sub_menu_clear">Clear</string>
<string name="fab_sub_menu_save_and_clear">Save and Clear</string>
<!-- dialogs -->
<string name="dialog_default_action_cancel">Cancel</string>
<string name="dialog_clear_content">Clear Recording?</string>
<string name="dialog_clear_action_clear">Clear</string>
<string name="dialog_delete_title">Delete Recording?</string>
<string name="dialog_delete_content">Delete this recording:</string>
<string name="dialog_delete_action_delete">Delete</string>
<string name="dialog_export_title_export">Export Recording as GPX?</string>
<string name="dialog_export_content_export">Export this recording as GPX track.</string>
<string name="dialog_export_action_export">Export</string>
<string name="dialog_export_title_overwrite">Export and Overwrite?</string>
<string name="dialog_export_content_overwrite">File already exists. Export and overwrite this recording as GPX track.</string>
<string name="dialog_export_action_overwrite">Export and Overwrite</string>
<!-- toast messages -->
<string name="toast_message_permissions_granted">Permissions granted.</string>
<string name="toast_message_unable_to_start_app">Unable to start Trackbook.</string>
<string name="toast_message_no_external_storage">Unable to access external storage.</string>
<string name="toast_message_location_offline">Location is turned off. Trackbook will not work.</string>
<string name="toast_message_acquiring_location">Acquiring current location.</string>
<string name="toast_message_location_services_not_ready">Location services not ready. Please retry.</string>
<string name="toast_message_last_location">Last location:</string>
<string name="toast_message_save_track">Saving current track.</string>
<string name="toast_message_last_location_age_one_hour">over one hour</string>
<string name="toast_message_track_clear">Current track data removed.</string>
<string name="toast_message_export_success">GPX export successful:</string>
<string name="toast_message_export_fail">GPX export failed:</string>
<!-- map markers -->
<string name="marker_description_source">Source</string>
<string name="marker_description_time">Time</string>
<string name="marker_description_accuracy">Accuracy</string>
<!-- statistics sheet -->
<string name="statistics_sheet_h1_statistics">Statistics</string>
<string name="statistics_sheet_p_default_data">track data missing</string>
<string name="statistics_sheet_p_distance">Total distance:</string>
<string name="statistics_sheet_p_steps">Steps taken:</string>
<string name="statistics_sheet_p_waypoints">Recorded waypoints:</string>
<string name="statistics_sheet_p_duration">Total duration:</string>
<string name="statistics_sheet_p_recording_start">Recording started:</string>
<string name="statistics_sheet_p_recording_stop">Recording stopped:</string>
<!-- onboarding layout -->
<string name="layout_onboarding_h1_welcome">Hello</string>
<string name="layout_onboarding_description_app_icon">Trackbook App Icon</string>
<string name="layout_onboarding_h2_app_name">Trackbook</string>
<string name="layout_onboarding_p_app_claim">Movement Recorder for Android</string>
<string name="layout_onboarding_h2_request_permissions">Trackbook cannot work without these permissions:</string>
<string name="layout_onboarding_h3_permission_location">LOCATION</string>
<string name="layout_onboarding_p_permission_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.</string>
<string name="layout_onboarding_h3_permission_storage">STORAGE</string>
<string name="layout_onboarding_p_permission_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.</string>
<string name="layout_onboarding_button_okay">Got it!</string>
<!-- track tab onboarding -->
<string name="track_tab_onboarding_h1_part_1">Your recorded tracks</string>
<string name="track_tab_onboarding_h1_part_2">… will show up here.</string>
<!-- infosheet about -->
<string name="infosheet_about_h1_about">About Trackbook</string>
<string name="infosheet_about_h2_recorder">Movement Recorder for Android</string>
<string name="infosheet_about_h3_version">Version 1.0 (Astronomy Domine)</string>
<string name="infosheet_about_p_bare">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).</string>
<string name="infosheet_about_p_free">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.</string>
<string name="infosheet_about_h2_permissions">Which Permissions does Trackbook need?</string>
<string name="infosheet_about_h3_internet">Permission INTERNET</string>
<string name="infosheet_about_p_internet">Trackbook needs to download map data from OpenStreetMap servers and therefore needs access to the internet.</string>
<string name="infosheet_about_h3_network">Permissions ACCESS_WIFI_STATE and ACCESS_NETWORK_STATE</string>
<string name="infosheet_about_p_network">Trackbook uses osmdroid to draw its maps. osmdroid needs to know the current state of your devices connectivity.</string>
<string name="infosheet_about_h3_location">Permissions ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION</string>
<string name="infosheet_about_p_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.</string>
<string name="infosheet_about_h3_external">Permission WRITE_EXTERNAL_STORAGE</string>
<string name="infosheet_about_p_external">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.</string>
<!-- descriptions -->
<string name="descr_map_current_track">Mapping of current track</string>
<string name="descr_map_last_track">Mapping of last track</string>
<string name="descr_fab_main">Main Action Button</string>
<string name="descr_fab_sub_menu_label_1">Label of the Save and Clear button</string>
<string name="descr_fab_sub_menu_button_1">small Save and Clear button</string>
<string name="descr_fab_sub_menu_label_2">Label of the Clear button</string>
<string name="descr_fab_sub_menu_button_2">small Clear button</string>
<string name="descr_statistics_sheet_headline">Headline of the statistics sheet</string>
<string name="descr_statistics_sheet_icon">Icon of a bar chart</string>
<string name="descr_statistics_sheet_p_distance">Data point: Distance</string>
<string name="descr_statistics_sheet_p_steps">Data point: Steps</string>
<string name="descr_statistics_sheet_p_waypoints">Data point: Waypoints</string>
<string name="descr_statistics_sheet_p_duration">Data point: Duration</string>
<string name="descr_statistics_sheet_p_recording_start">Data point: Start of recording</string>
<string name="descr_statistics_sheet_p_recording_end">Data point: End of recording</string>
<string name="descr_statistics_sheet_p_distance_value">Value: Distance</string>
<string name="descr_statistics_sheet_p_steps_value">Value: Steps</string>
<string name="descr_statistics_sheet_p_waypoints_value">Value: Waypoints</string>
<string name="descr_statistics_sheet_p_duration_value">Value: Duration</string>
<string name="descr_statistics_sheet_p_recording_start_value">Value: Start of recording</string>
<string name="descr_statistics_sheet_p_recording_end_value">Value: End of recording</string>
<string name="descr_track_selector">Dropdown menu for further tracks</string>
<string name="descr_export_button">Track export button</string>
<string name="descr_delete_button">Track delete button</string>
</resources>

View File

@ -23,6 +23,8 @@
<string name="notification_swipe_to_clear_map">(scorri per spostare la mappa)</string>
<string name="notification_content_duration">Durata</string>
<string name="notification_content_distance">Distanza</string>
<string name="notification_channel_recording_name">Movement Recording State</string>
<string name="notification_channel_recording_description">Display duration and distance. Option to stop movement recording.</string>
<!-- snackbar messages -->
<string name="snackbar_message_tracking_stopped">Tracciamento interrotto</string>

View File

@ -18,6 +18,8 @@
<string name="notification_swipe_to_clear_map">(スワイプしてマップをクリア)</string>
<string name="notification_content_duration">期間</string>
<string name="notification_content_distance">距離</string>
<string name="notification_channel_recording_name">Movement Recording State</string>
<string name="notification_channel_recording_description">Display duration and distance. Option to stop movement recording.</string>
<string name="snackbar_message_tracking_stopped">トレースを停止しました</string>
<string name="snackbar_message_tracking_started">トレースを開始しました</string>

View File

@ -18,6 +18,8 @@
<string name="notification_swipe_to_clear_map">(sveip for å tømme kart)</string>
<string name="notification_content_duration">Varighet</string>
<string name="notification_content_distance">Distanse</string>
<string name="notification_channel_recording_name">Movement Recording State</string>
<string name="notification_channel_recording_description">Display duration and distance. Option to stop movement recording.</string>
<string name="snackbar_message_tracking_stopped">Sporing stoppet</string>
<string name="snackbar_message_tracking_started">Sporing startet</string>

View File

@ -18,6 +18,8 @@
<string name="notification_swipe_to_clear_map">(veeg om kaart te wissen)</string>
<string name="notification_content_duration">Duur</string>
<string name="notification_content_distance">Afstand</string>
<string name="notification_channel_recording_name">Movement Recording State</string>
<string name="notification_channel_recording_description">Display duration and distance. Option to stop movement recording.</string>
<string name="snackbar_message_tracking_stopped">Bijhouden gestopt</string>
<string name="snackbar_message_tracking_started">Bijhouden gestart</string>

View File

@ -23,6 +23,8 @@
<string name="notification_swipe_to_clear_map">(swipe to clear map)</string>
<string name="notification_content_duration">Duration</string>
<string name="notification_content_distance">Distance</string>
<string name="notification_channel_recording_name">Movement Recording State</string>
<string name="notification_channel_recording_description">Display duration and distance. Option to stop movement recording.</string>
<!-- snackbar messages -->
<string name="snackbar_message_tracking_stopped">Tracking stopped</string>

View File

@ -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'
}
}