Skip to content

FINAL PROJECT

Final Project - GPS SportMap

Final Deadline 2023-XX-XX 23:59:59

App like endomondo, nike run, strava, runtastic, etc.

General idea - app, that would help you in unknown terrain with navigation and training. App is based on Google Maps (or openstreetmap or some other) and built-in GPS functionality.

Display map, and update your location on map display.
Allow toggling of "keep map constantly centered", "keep north-up / direction up / user chosen-up".

When tracking is started, start to draw trail from start to current location.
Allow user to set checkpoints (permanent) and waypoints (single) on track. Ie when adding new waypoint, remove previous.
Calculate and display direct and travelled distance from start, last checkpoint and last waypoint. Time elapsed from start, overall pace (in minutes per km) in every three sections.

Save all the sessions and all the checkpoints to database.
Allow user to view/delete old sessions - display statistics and track on map.

For controlling the app from lock screen, implement sticky custom layout notification - UI similar to what you have under the map. When user stops session, ask for confirmation. Do not let to start/stop session from lock-screen. Constantly(after every position update) update notification to display current info - distances and pace.

GPS listener and notification intents broadcast listener has to be implemented in service, otherwise app cannot be kept running in background.

App has to support rotation (and state has to be restored) - move buttons from bottom to left-or-right screen edge in landscape mode.

Provide on-screen real compass (must be possible to turn on-and-off). Google maps rotation indicator is not a compass.

Provide session export possibility - ie as email attachment for example. File format - gpx.
https://www.topografix.com/gpx_manual.asp (checkpoints as waypoints in gpx format).
Gpx entries have to contain coordinates of every location update and user set WP coordinates and timestamp (for later track analysis and animation).

Allow creating user account and sync data to central Web-API/Rest backend (provided by teacher).

Change app icon into something more meaningful.

Checkpoint - CP - some predefined marked location on terrain and on paper map. When you did find the CP, mark it's location in app. Gets saved to DB.

Waypoint - WP - temporary marker, used to measure smaller segments on terrain to find path to next CP. When placing new WP, previous one is removed. WPs do not get saved to DB.

Backend service - Web-API/Rest service. Web based visualization of map and tracks on map (realtime).
https://sportmap.akaver.com

https://git.akaver.com/native-mobile-apps-2020-fall/course-materials/-/blob/master/hw/HW3-backend.md

Demo of Fused location in background foreground service https://git.akaver.com/native-mobile-apps-2020-fall/course-materials/-/tree/master/android/fusedlocationbackground

Google map demo https://git.akaver.com/native-mobile-apps-2020-fall/course-materials/-/tree/master/android/sportmapdemo
https://git.akaver.com/native-mobile-apps-2020-fall/course-materials/-/tree/master/android/GPSMapDemo

Rest api demo https://git.akaver.com/native-mobile-apps-2020-fall/course-materials/-/tree/master/android/RestDemo
https://git.akaver.com/native-mobile-apps-2020-fall/course-materials/-/tree/master/android/webapidemo

Examples of possible UI-s https://git.akaver.com/native-mobile-apps-2020-fall/course-materials/-/tree/master/hw/hw3-screens

Demo of compass in kotlin https://andreas-mausch.de/blog/2017/05/14/compass-app-in-kotlin/
https://github.com/andreas-mausch/compass

Ascii art of possible UI

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
--------------------------------------
North-Up    Reset   Compass   Options








            Google Map area

--------------------------------------
Start  15 000 | add   1500 |  add  783
 or   1:35:47 |  CP   1137 |  WP   332
stop     8:45 | icon  6:37 | icon 7:35

Explanation of numbers in UI:

Section1 - Overall
Distance covered (meters)
Session duration hh:mm:sec
Average speed (minutes per 1 kilometer)

Section2 - Checkpoint
Distance covered from CP to current location
Direct line distance from CP to current location
Average speed

Section3 - Waypoint
Distance covered from WP to current location
Direct line distance from WP to current location
Average speed

Approximate schedule for pacing the workload

2023-XX-XX 23:59:59

Google maps is visible, ui is receiving updates from background location service. It is possible to start and stop the tracking, set CPs and WPs from main screen.
Main activity primary UI is done, rotation works correctly in layout. All screen sizes are supported. even tablets.

2023-XX-XX 23:59:59

Custom notifications are implemented, it is possible to control app from the lock screen.
App works in background.

2023-XX-XX 23:59:59

Database is working, sessions get saved to database, it is possible to view/rename/delete old sessions. Allow zooming into track of old sessions. Track segments are gradient colored according to speed (define range of colors/speed) - both in old and current session.
Example: http://omaps.akaver.com/show_map.php?user=akaver&map=273
App is working correctly in background (locked screen). Ui is restored correctly after unlock.

2023-XX-XX 23:59:59

User can create an account in app, account info is saved locally. Account gets created in backend server. Session start and location updates are synced realtime to backend service during active session. Track segment coloring is easily user configurable - per active session and also in every past session separately (sometimes optimal range is 4-7, sometimes 7-20 minutes per km).

2023-XX-XX 23:59:59

Everything is ready, you are ready to discuss your code with teacher 1-to-1. Some final touches and real world testing maybe still needs to be done.
Defence of your code is mandatory!

Syncing is working, you can change syncing interval in options (ala when received, once in 10 sec, once in 30, sec, etc..). It is possible to change gps update frequency. Gps location coordinates are filtered, obvious wrong coordinates are filtered out (ie impossible x hundred meter jumps).

2023-XX-XX 23:59:59

End of semester, defence of app will be conducted in some nearby forest terrain, using teacher provided paper map and your app (code has to be defended first).

It's done, you are ready to tackle unseen forest using your app. You have tested it extensively, it will not crash even while doing some 2-3h long session. Syncing to backend works, even if there is no data connection - you can sync all the locations later.

Use your app to find hidden checkpoints in terrain - take photo of every cp and present these and your track (gpx) (sent as email attachment to teacher) after completing the exercise.

GPX in ios

https://github.com/merlos/iOS-Open-GPX-Tracker

Backend

All projects for SportMap:
https://git.akaver.com/com-akaver-sportmap

Full source code for the backend is visible here:
https://git.akaver.com/com-akaver-sportmap/sportmap-aspnet

ERD schema is simple:

  • GpsSession - training sessions
  • GpsLocation - locations for session (WP, CP, regular)
  • GpsLocationType - LocationTypes for location

Base url for RESTful api: https://sportmap.akaver.com/api/v1.0/

Check the latest api version from swagger documentation: https://sportmap.akaver.com/swagger/index.html

Set the header on every request:
Content-Type application/json

Create account, log in - get and save the jwt.
POST https://sportmap.akaver.com/api/v1.0/account/register
Payload in body as json:

1
2
3
4
5
6
{
    "email": "akaver1@akaver.com",
    "password": "Kala.maja2020",
    "lastName": "Andres",
    "firstName": "Käver"
}

or

POST https://sportmap.akaver.com/api/v1.0/account/login
Payload in body as json:

1
2
3
4
{
    "email": "akaver1@akaver.com",
    "password": "Kala.maja2020",
}

Response for successful register and login:

1
2
3
4
{
    "token": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjU2MGIxMWM5LWVlYTYtNDNhMy1jYTViLTA4ZDdlMTc3MGNhOSIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJha2F2ZXJAYWthdmVyLmNvbSIsIkFzcE5ldC5JZGVudGl0eS5TZWN1cml0eVN0YW1wIjoiMlozVzZEMkozT1RTS0dNQ0xMU09IM1ZZS1pUQkxYRk4iLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOlsidXNlciIsImFkbWluIl0sImV4cCI6MTU4OTYxNDczNSwiaXNzIjoiY29tLmFrYXZlci5zcG9ydG1hcCIsImF1ZCI6ImNvbS5ha2F2ZXIuc3BvcnRtYXAifQ.B0YNH-0rUgethh3TgdQXV7s3PcM87OgQBPJ2VTnBnw4d64dG4z-V4QztKbwYyPUNRtdzc7Gc89Bdsi2egYjdgA",
    "status": "User akaver@akaver.com logged in."
}

On every request include token and content-type in request header:
Authorization Bearer eyJhbGciOiJIU...
Content-Type application/json

There are 3 RESTful endpoints defined for your app:

  • https://sportmap.akaver.com/api/v1.0/GpsSessions
  • https://sportmap.akaver.com/api/v1.0/GpsLocations
  • https://sportmap.akaver.com/api/v1.0/GpsLocationTypes

Start a new session:
POST https://sportmap.akaver.com/api/v1.0/GpsSessions
Payload in body as json:

1
2
3
4
5
6
7
{
"name": "2020-04-15",
"description": "2020-04-15 evening run",
"recordedAt": "2020-04-15T23:41:57.352165+03:00",
"minSpeed": 420,
"maxSpeed": 600,
}

Response will be:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
{
    "name": "2020-04-15",
    "description": "2020-04-15 evening run",
    "recordedAt": "2020-04-15T23:41:57.352165+03:00",
    "duration": 0,
    "speed": 0,
    "distance": 0,
    "climb": 0,
    "descent": 0,
    "appUserId": "560b11c9-eea6-43a3-ca5b-08d7e1770ca9",
    "id": "b310e8ce-eebd-47b0-91c3-08d7e17d70ab"
}
~~~~

Save the session id!  
Duration, speed etc will be calculated by the backend as data arrives.  

Get the list of location types (these are predefined in db, id's and types are fixed)  
GET https://sportmap.akaver.com/api/v1.0/GpsLocationTypes

Response will be:

~~~~json
[
    {
        "name": "LOC",
        "description": "Regular periodic location update",
        "id": "00000000-0000-0000-0000-000000000001"
    },
    {
        "name": "WP",
        "description": "Waypoint - temporary location, used as navigation aid",
        "id": "00000000-0000-0000-0000-000000000002"
    },
    {
        "name": "CP",
        "description": "Checkpoint - found on terrain the location marked on the paper map",
        "id": "00000000-0000-0000-0000-000000000003"
    }
]
~~~~

Post the location updates to backend:  
POST https://sportmap.akaver.com/api/v1.0/GpsLocations  
Payload in body as json:  

~~~json
{
    "recordedAt": "2020-04-15T23:51:57.352165+03:00",
    "latitude": 23.456,
    "longitude": 59.789,
    "accuracy": 15.5,
    "altitude": 75.7,
    "verticalAccuracy": 13.9,
    "gpsSessionId": "b310e8ce-eebd-47b0-91c3-08d7e17d70ab",
    "gpsLocationTypeId": "00000000-0000-0000-0000-000000000001"
}